- lucene的索引的修改和删除
- solr:
-
- solr的概念
-
- solr的部署(2种方式)
-
- solr的管理界面
-
- solr的配置文件: solrConfig.xml schema.xml core.properties
-
- solrj 连接solr 相关的操作: C U R D
-
- solr的高级: 高亮 分页 排序
-
1. lucene的索引的修改和删除
- 索引的修改
public class LuceneEdit {
//lucene的修改, 本质上先删除原有的数据, 然后进行添加索引
public static void main(String[] args) throws IOException {
//1. 创建索引写入器对象
Directory directory = FSDirectory.open(new File("f:\\index"));
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST,new IKAnalyzer());
IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig);
//2. 修改索引
Document doc = new Document(); //此处的document是修改后的数据
doc.add(new LongField("id",21L, Field.Store.YES));
doc.add(new StringField("title","今天讲solr了,这是修改后的内容", Field.Store.YES));
indexWriter.updateDocument(new Term("title","lucene的简介"),doc);
//3. 提交索引
indexWriter.commit();
//4. 关闭
indexWriter.close();
}
}
- lucene的索引的删除
public class LuceneDelete {
//索引的删除
public static void main(String[] args) throws IOException {
//1. 创建indexWriter对象
Directory directory = FSDirectory.open(new File("f:\\index"));
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST,new IKAnalyzer());
IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig);
//2. 索引的删除
indexWriter.deleteAll();//删除全部
//indexWriter.deleteDocuments(query);//根据条件删除
//indexWriter.deleteDocuments(new Term("title","今天讲solr了,这是修改后的内容"));//根据词条删除
//3. 提交
indexWriter.commit();
//4. 关闭
indexWriter.close();
}
}
2. solr
solr是一个独立的企业级的搜索应用服务器, 如果想从服务器中获取数据, 那么就需要使用http请求发送, solr的是基于lucene实现的, 底层就是lucene
3.solr的部署
3.1 solr的下载:
- 通过官方网址: http://lucene.apache.org/ 和lucene是一样的, 这个网址只能下载最新版本的solr
- 下载历史的版本: http://archive.apache.org/dist/lucene/solr/
3.2 solr的目录结构
3.3 solr服务的部署
3.3.1 使用start.jar部署solr服务
- 部署步骤:
-
- 打开cmd, 切换start.jar这个目录下
-
- 执行 java -jar start.jar
-
- 访问管理界面: localhost:8983/solr
-
3.3.2 使用solr.war进行部署(重点)
准备工作:
在一个没有中文和空格的地方, 创建一个目录, 目录名(solr), 把tomcat放置到solr目录中
在使用tomcat之前, 先进行tomcat的测试(启动一个tomcat)
如果tomcat已启动就闪退:
检查jdk的环境变量:
jdk的环境错误: JAVA_HOME 此单词写错了
-
步骤1: 先将solr.war放置到一个空的tomcat中的webapps目录下
-
第二步: 启动tomcat, 解压solr.war
- 注意: 启动解压完毕以后, 请必须将tomcat关闭
-
第三步: 将原来solr.war删除, 或者更改其后缀名称
-
第四步: 打开解压后的solr目录, 从资料中将tomcat运行的jar包和配置文件复制到solr里面去
-
第五步: 复制example里面的solr目录里面的所有的内容, 将其复制到 和tomcat同级的目录(solr-home)中
-
第六步: 打开tomcat中bin目录下的Catalina.bat
-
第七步: 设置如下的参数:保存关闭
- 内容
set "JAVA_OPTS=-Dsolr.solr.home=D:\JAVA_Soft\solr\solr-home"
- 第八步:启动tomcat, 测试, 是否成功
4. solr的管理界面
-
仪表盘
-
logging: 日志显示
解决一下警告(可选):
-
第一步:
-
第二步: 修改配置文件
-
core admin
如何配置多个索引库:(推荐一种比较简单的方案)
-
第一步: 将collection1复制出来一个, 进行更改名称(名称可以自定义)
-
第二步: 打开新复制的出来的索引库, 找到core.properties,打开此文件
-
第三步: 修改此配置文件中的name名称(自定义, 可以不和文件名称一致)
-
重新启动tomcat即可
建议: 在设置一个新的索引库的时候, 建议将新复制出来的索引库中data的目录删除掉
-
core selector
-
documents
-
query
-
schema browser
5. solr的配置文件
5.1 solrConfig.xml:
solrconfig.xml 配置文件主要定义了 solr 的一些处理规则,包括索引数据的存放 位置,更新,删除,查询的一些规则配置。
一般此文件不需要进行修改, 采取默认即可
在实际的使用中: 一般这个文件可以做相关solr的优化的
5.2 schema.xml:约束文件
在schema文件中, 指定了solr的字段, 字段类型, 使用什么分词器, 主键相关设置
<schema name="example" version="1.5">
<!-- 不删除
-->
<field name="_version_" type="long" indexed="true" stored="true"/>
<field name="_root_" type="string" indexed="true" stored="false"/>
<!-- 不删除
field: 字段, 指定文档的字段的
name: 字段的名称
type: 字段的类型
indexed: 是否索引
stored: 是否存储
required: 是否必须
multiValued: 是否多值(此字段是一个数组)
id这个字段: 是solr的文档的主键字段, 必须进行设置, 这是文档的唯一标识
id在solr中是需要程序员自己维护, lucene文档的id是有lucene自己维护的
-->
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="name" type="string" indexed="true" stored="true"/>
<field name="title" type="string" indexed="true" stored="true" multiValued="true"/>
<field name="content" type="string" indexed="false" stored="true" multiValued="true"/>
<field name="text" type="string" indexed="true" stored="false" multiValued="true"/>
<!--
dynamicField: 动态域, solr中无法将所有的字段全部都定义好,此时solr为了能够进行扩展, 采用动态域
当进行添加文档的时候, 只需要保证其后缀的名称和动态域的名称一致即可, 这样就可以添加任意的字段了
-->
<dynamicField name="*_t" type="string" indexed="true" stored="true"/>
<!--
uniqueKey :唯一主键 , 此处是用于定义主键字段的
solr支持给任意字段设置为主键, 但是一般不这么干, 通常都是使用id
-->
<uniqueKey>id</uniqueKey>
<!--
copyField: 复制域, 主要是用来做搜索的, 可以将其他多个字段的数据合并到一个字段里面去, 这样当查询复制域的字段的时候
就相关于查询了多个字段
source: 来源字段, 复制那个字段
dest: 目的字段, 将数据复制到那个字段里面去
-->
<copyField source="title" dest="text"/>
<copyField source="content" dest="text"/>
<!--
fieldType: 字段的类型, 指定某个字段的类型的, 可以指定字段类型使用分词器
-->
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
<!-- boolean type: "true" or "false" -->
<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
<fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="date" class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0"/>
</schema>
5.3 引入ik分词器
- 第一步: 导入ik分词器的jar包
- 这一步骤在部署solr的时候, 已经就将其复制到了solr的lib目录里面去了
- 第二步: 导入ik分词器的配置文件
- 这一步其实已经做了, 在部署tomcat的时候导入一个classes,
- 第三步: 修改schema.xml配置文件, 添加ik分词器的字段类型
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
- 第四步: 给指定的字段设置此字段类型
注意: 在进行配置文件修改的时候, 请按照以下的修改
- 第五步: 测试ik是否正常使用
6 solrj
solrj: 是apache开发的一个java连接solr的服务器的工具包, 使用solrj就可以对solr服务中数据进行CURDL
6.1 基本入门
- 第一步: 导包
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>4.10.2</version>
</dependency>
<!--日志的包, solrj执行需要一个日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
<version>1.1</version>
</dependency>
- 第二步: 编写代码(写入索引库的操作)
public class IndexWriterToSolr {
@Test
public void indexWriterToOne() throws IOException, SolrServerException {
//1. 创建solrj连接solr的服务端对象
/*
* http://localhost:8080/solr/itcast: solr的接口的url
*
* http://localhost:8080/solr/#/itcast: 是浏览器的url
* */
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/itcast");
List<SolrInputDocument> list = new ArrayList<SolrInputDocument>();
for(int i = 1 ; i<=10 ; i++){
//2. 添加document对象
SolrInputDocument doc = new SolrInputDocument();
//2.1 向文档中添加数据
//注意: 字段的名称必须是schema中定义好的, 要不然就使用动态域
doc.addField("id",i);
doc.addField("name","*");
doc.addField("content","**");
doc.addField("age",58+i);
list.add(doc);
}
//solrServer.add(doc);
solrServer.add(list);
//3. 提交文档
solrServer.commit();//提交的时候, 就当于发送了一个请求
}
}
- 使用javaBean添加索引
@Test
public void indexWriterToTwo() throws IOException, SolrServerException {
//1. 创建solrServer服务对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/itcast");
List<User> list = new ArrayList<User>();
//2. 添加文档
for(int i = 12 ;i<=17; i++){
User user = new User();
user.setId(i+"");
user.setName("*");
user.setAge(78+i+"");
user.setTitle(new String[]{"**"});
user.setContent("***");
list.add(user);
}
//solrServer.addBean(user);
solrServer.addBeans(list);
//3. 提交数据
solrServer.commit();
}
6.2 删除索引
public class DeleteIndexToSolr {
@Test
public void deleteIndex() throws IOException, SolrServerException {
//1. 创建solrServer服务对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/itcast");
//2. 执行删除: 字段名称:字段的值
//solrServer.deleteByQuery("age:59");
solrServer.deleteById("2");
//3. 提交
solrServer.commit();
}
}
6.3 索引的查询
6.3.1 基本查询的入门程序
@Test
public void queryToSolrofOne() throws SolrServerException {
//1. 创建solrj连接solr的服务对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/itcast");
//2. 执行查询
SolrQuery solrQuery = new SolrQuery("*:*");
solrQuery.setRows(100);
QueryResponse response = solrServer.query(solrQuery);
//3. 获取数据: document对象
SolrDocumentList documentList = response.getResults();
//4. 遍历集合 ,获取数据
for (SolrDocument document : documentList) {
Object id = document.get("id");
Object age = document.get("age");
Object content = document.get("content");
System.out.println(id+" "+age+ " "+ content);
}
}
- 返回javaBean的形式
public class User {
// @Field: 指定当前这个成员属性是一个solr的字段
@Field
private String id;
@Field
private String name;
@Field
private Integer age;
@Field
private String content;
@Field
private String[] title;
//缺失 get 和set
}
- 编写代码
//返回javaBean
@Test
public void queryToSolrofTwo() throws SolrServerException {
//1. 创建solrServer服务对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/itcast");
//2. 执行查询
QueryResponse response = solrServer.query(new SolrQuery("*:*"));
//3. 解析结果:
// 注意: 当返回的是javaBean的时候, 一定要注意, javaBean必须有无参构造
List<User> userList = response.getBeans(User.class);
for (User user : userList) {
System.out.println(user);
}
}
6.3.2 多样化的查询
在创建SolrQuery时,我们填写的Query语句,可以有以下高级写法:
查询语句中如果有特殊字符,需要转义,可以使用: ” ”
1、匹配所有文档:*? (通配符?和 * :“*”表示匹配任意字符;“?”表示匹配出现的位置)
2、布尔操作:AND、OR和NOT布尔操作(推荐使用大写,区分普通字段)
3、子表达式查询(子查询):可以使用“()”构造子查询。 比如:(query1 AND query2) OR (query3 AND query4)
4、相似度查询:
(1)默认相似度查询:title:appla~,此时默认编辑距离是2
(2)指定编辑距离的相似度查询:对模糊查询可以设置编辑距离,可选02的整数:title:appla1。
5、范围查询(Range Query):Lucene支持对数字、日期甚至文本的范围查询,并且两端范围。结束的范围可以使用“*”通配符。
(1)日期范围(ISO-8601 时间GMT):birthday:[1990-01-01T00:00:00.000Z TO 1999-12-31T24:59:99.999Z]
(2)数字:age:[2000 TO *]
(3)文本:content:[a TO a]
- 通配符的查询
//统配符查询
// ? : 占用一个符号
// * : 占用 0 到 多个
@Test
public void queryToSolrofThree() throws SolrServerException {
//1. 创建 solrServer服务对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/itcast");
//2. 执行查询
SolrQuery solrQuery = new SolrQuery("title:简*");
QueryResponse response = solrServer.query(solrQuery);
//3. 解析结果:
// 注意: 当返回的是javaBean的时候, 一定要注意, javaBean必须有无参构造
List<User> userList = response.getBeans(User.class);
for (User user : userList) {
System.out.println(user);
}
}
- 布尔查询
//布尔查询
// AND OR NOT
//当使用java代码进行查询的时候, 发现没有获取到数据,是不是代码写的有问题
// 直接将条件内容, 放置到solr的管理界面进行测试执行
@Test
public void queryToSolrof4() throws SolrServerException {
SolrQuery solrQuery = new SolrQuery("title:简介 NOT age:95 NOT age:90");
baseQuery(solrQuery);
}
- 子查询
//子查询
@Test
public void queryToSolrof5() throws SolrServerException {
SolrQuery solrQuery = new SolrQuery("(title:简介 NOT age:95) AND (content:javaweb OR name:*)");
baseQuery(solrQuery);
}
- 相似度查询
//相似度查询: lucene的模糊查询
// 最大编辑次数: 2次
// 在solr中使用 ~
// solr中 ~后面添加了大于2 , 使用默认为2
// 如果~ 后面添加小于0的, 使用默认为2
@Test
public void queryToSolrof6() throws SolrServerException {
// javaweb~
SolrQuery solrQuery = new SolrQuery("content:javaw~");
baseQuery(solrQuery);
}
- 范围查询
//范围查询
// 格式: [起始值 TO 结束值] 包含边界值
@Test
public void queryToSolrof7() throws SolrServerException {
//字典顺序
SolrQuery solrQuery = new SolrQuery("id:[2 TO 9]");
baseQuery(solrQuery);
}
7. solr高级
7.1 solr的排序
//solr的排序
@Test
public void solrSort() throws SolrServerException {
SolrQuery solrQuery = new SolrQuery("*:*");
//solrQuery.setSort(new SolrQuery.SortClause("age", SolrQuery.ORDER.desc));
solrQuery.setSort("age", SolrQuery.ORDER.desc);
baseQuery(solrQuery);
}
7.2 solr的分页
@Test
public void limitToSolr() throws SolrServerException {
//分页的参数
int page = 3;
int rows = 3;
SolrQuery solrQuery = new SolrQuery("*:*");
solrQuery.setStart((page-1)*rows); //设置起始值
solrQuery.setRows(rows); //每页显示的条数
baseQuery(solrQuery);
}
7.3 solr的高亮
@Test
public void highlighterToSolr() throws SolrServerException {
//1. 创建solrServer
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/itcast");
//2. 执行查询
SolrQuery solrQuery = new SolrQuery("content:javaweb");
solrQuery.setHighlight(true);//开启高亮
solrQuery.addHighlightField("content");//设置高亮的字段
solrQuery.setHighlightSimplePre("<font color='red'>");
solrQuery.setHighlightSimplePost("</font>");
QueryResponse response = solrServer.query(solrQuery);
/**
* 最外层的map:
* key: 文档的id值
* value: 当前文档的高亮内容
* 内层的map:
* key: 高亮的字段
* value: 高亮的内容(list一般只有一个)
*
*/
Map<String, Map<String, List<String>>> map = response.getHighlighting();
//单独获取高亮的内容
for (String key : map.keySet()) {
Map<String, List<String>> stringListMap = map.get(key);
for (String fieldKey : stringListMap.keySet()) {
List<String> list = stringListMap.get(fieldKey);
System.out.println(list.get(0));
}
}
//3. 获取javaBean
List<User> userList = response.getBeans(User.class);
for (User user : userList) {
//与结果集进行结合
Map<String, List<String>> map1 = map.get(user.getId());
user.setContent(map1.get("content").get(0));
System.out.println(user);
}
}
}