solr环境配置
安装solr前,请确保系统中已正确安装jdk8,tomcat8和环境变量的配置。
solr下载及解压
使用命令:
wget http://mirrors.tuna.tsinghua.edu.cn/apache/lucene/solr/7.4.0
从官网下载solr压缩包
解压:
tar -zxvf solr-7.4.0.tgz
配置tomcat启动solr
solr自带jetty启动,这里使用tomcat进行配置启动。
- 在tomcat包下的webapps目录新建一个目录,取名solr
- 将solr解压包/solr-7.4.0/server/solr-webapp/webapp/下的内容拷贝到刚才tomcat下新建的文件夹solr中
- 将/solr-7.4.0/server/lib/ext/下的jar包拷贝到/tomcat/webapps/solr/WEB-INF/lib/下
- 将/solr-7.4.0/server/lib/下metrics开头的jar包也拷贝到刚才的目录下
- 将/solr-7.4.0/dist/下 solr-dataimporthandler-extras-7.4.0.jar、solr-dataimporthandler-7.4.0.jar也拷贝到刚才的目录下
- 在你本地的/home下新建一个文件夹,取名solr-home,将/solr-7.4.0/server/solr下的内容拷贝到刚才新建的solr-home下
- 打开并编辑/tomcat/webapps/solr/WEB-INF/web.xml
内容如下:
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/home/solr-home</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
并注释文件末尾的所有 元素节点。
配置solr日志
将/solr-7.4.0/server/resources/下的log4j2.xml文件拷贝到/tomcat/webapps/solr/WEB-INF/classes/下,如果没有则自己创建一个。
创建core
- 在/home/solr-home/下创建一个文件夹,文件夹名称为你的core名称,这里设为collection
- 将/solr-7.4.0/example/example-DIH/solr/solr下的内容拷贝到刚才创建的collection下,同时在core.properties下添加如下内容:
name=collection
启动tomcat,访问 localhost:8080/solr/index.html 就可以看到solr的界面了。
安装IK分词器
1.解压IK分词器的压缩包,进入文件夹
2.将IK分词器的jar包放置到tomcat下solr的WEB_INF下的lib里
3.将IK分词器的conf下的IKAnalyzer.cfg.xml和stopword.dic放置到tomcat下solr的WEB_INF下的classes里(没有classes文件夹务必创建一个)
4.修改/home/solr-home下collection下的managed-schema.xml,添加
<fieldType name="text_ik" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false"/>
<!-- <filter class="org.wltea.analyzer.lucene.IKTokenFilterFactory" useSingle="true" useItself="false" /> -->
</analyzer>
<analyzer type="query">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false"/>
<!-- <filter class="org.wltea.analyzer.lucene.IKTokenFilterFactory" useSingle="true" useItself="false" /> -->
</analyzer>
</fieldType>
这其实就是分词器的描述,配置的text_ik就是下图分词器的名字了
使用分词器
重启tomcat,进入对应的index.html,如下图操作
对比两个分词的效果
自带分词
IK分词器
Java对Solr索引操作
1.引入Solr对SpringBoot的依赖
dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
</dependency>
2.配置yml
spring:
data:
solr:
#这里的host地址对应配置的solrhome/collection/core.properties中的name的值
host: http://192.168.9.128:8081/solr/collection
3.引入索引solr客户端
@Autowired
private SolrClient solrClient;
4.Solr索引的新增
public void solrAddOne() throws IOException, SolrServerException {SolrInputDocument solrInputFields = new SolrInputDocument();
solrInputFields.addField("id",10);
solrInputFields.addField("goodsName","华为手机是中国手机的领导者,华为");
solrInputFields.addField("age","22");
solrInputFields.addField("sex","男");
//将索引对象保存到索引库中(id相同就是修改)
solrClient.add(solrInputFields);
solrClient.commit();
}
5.删除索引
/*删除索引库*/
@Test
public void solrDelete() throws IOException, SolrServerException {
//根据id删除
solrClient.deleteById("1");
//根据能查询到的结果删除(根据商品名为华为的删除)
//solrClient.deleteByQuery("goodsName:华为");
solrClient.commit();
}
6.索引修改
//通过新增同样的id,相当于覆盖,但是注意是修改整个索引,包括age属性(被Null覆盖了)
public void solrAddOne() throws IOException, SolrServerException {SolrInputDocument solrInputFields = new SolrInputDocument();
solrInputFields.addField("id",10);
solrInputFields.addField("goodsName","华为手机修改过后的值是华为2");
//将索引对象保存到索引库中(id相同就是修改)
solrClient.add(solrInputFields);
solrClient.commit();
}
> QueryResponse类中有几个方法
| 方法名 | 返回值 | 返回值说明 |
| ----------------- | ------------------------------------ | -------------------------------------------------- |
| getResults() | SolrDocumentList | 本身就是一个ArrayList,包含了结果 |
| getHighlighting() | Map<String,Map<String,List<String>>> | 1:{goodsName=[<font color='red'>华为</font>手机1]} |
result结构图
![1542186163863](C:\Users\user\Documents\1542186163863.png)
```java
@Test
public void query() throws IOException, SolrServerException {
SolrQuery solrQuery = new SolrQuery();
//执行查询 id是5的索引
solrQuery.setQuery("id:5");
QueryResponse response = solrClient.query(solrQuery);
SolrDocumentList results = response.getResults();
for (SolrDocument result : results) {
String goodsName = (String) result.getFieldValue("goodsName");
Collection<String> fieldNames = result.getFieldNames();
System.out.println(goodsName);
System.out.println("---------------------------------------------");
for (String fieldName : fieldNames) {
System.out.print(fieldName);
System.out.println(result.getFieldValue(fieldName));
}
}
}
索引在项目中文字高亮
京东淘宝或者百度都会在搜索时,将关键字进行变色等高亮处理,solr支持对搜索关键字高亮
方法介绍
Solr查询类SolrQuery中有几个方法,作用如下
方法名 | 作用 |
---|---|
setHighlight(boolean b) | 是否高亮 |
setHighlightSimplePre(String f) | 规定高亮文字的样式(前) |
setHighlightSimplePost(String f) | 规定高亮文字的样式(后) |
setHighlightSnippets(int num) | 结果分组:规定查询的文字分成几部分 |
setHighlightFragsize(int num) | 规定每部分文字的字数 |
创建一个关键字查询方法接口
@RequestMapping("/query")
public String query(String key,Model model) throws IOException, SolrServerException {
SolrQuery solrQuery = new SolrQuery();
//设置查询的内容
if (key.equals("")) {
solrQuery.setQuery("*:*");
} else {
solrQuery.setQuery("goodsName:"+key);
}
//设置高亮的格式:前缀后缀
solrQuery.setHighlight(true);
solrQuery.setHighlightSimplePre("<font color='red'>");
solrQuery.setHighlightSimplePost("</font>");
solrQuery.addHighlightField("goodsName");
//分成几部分,每部分长度
solrQuery.setHighlightSnippets(2);
solrQuery.setHighlightFragsize(5);
QueryResponse query = solrClient.query(solrQuery);
SolrDocumentList results = query.getResults();
Map<String, Map<String, List<String>>> highlighting = query.getHighlighting();
List<Goods> goodList = new ArrayList<>();
for (SolrDocument result : results) {
Goods goods = new Goods();
Integer id = Integer.parseInt(result.getFieldValue("id")+"");
if (highlighting.containsKey(id+"")) {
List<String> goodsNameList = highlighting.get(id + "").get("goodsName");
StringBuilder sb = new StringBuilder();
for (String goodsName : goodsNameList) {
sb.append(goodsName);
}
goods.setGoodsName(sb.toString());
}
goods.setAge(Integer.parseInt(result.getFieldValue("age")+""));
goods.setSex((String) result.getFieldValue("sex"));
goodList.add(goods);
}
注意以上setHighlightSnippets()方法中,如果给出的参数>1,即分成多部分内容,那上面goodsNameList集合就不是一个,而是多个,可以通过拼接的方式显示出来.
原本存在的索引
{
"responseHeader": {
"status": 0,
"QTime": 0,
"params": {
"q": "*:*"
}
},
"response": {
"numFound": 10,
"start": 0,
"docs": [
{
"id": "0",
"goodsName": "华为手机0",
"age": "220",
"_version_": 1617089328451682304
},
{
"id": "2",
"goodsName": "华为手机2",
"age": "222",
"_version_": 1617089328509353984
},
{
"id": "3",
"goodsName": "华为手机3",
"age": "223",
"_version_": 1617089328516694016
},
{
"id": "4",
"goodsName": "华为手机4",
"age": "224",
"_version_": 1617089328524034048
},
{
"id": "5",
"goodsName": "华为手机5",
"age": "225",
"_version_": 1617089328531374080
},
{
"id": "6",
"goodsName": "华为手机6",
"age": "226",
"_version_": 1617089328538714112
},
{
"id": "7",
"goodsName": "华为手机7",
"age": "227",
"_version_": 1617089328546054144
},
{
"id": "8",
"goodsName": "华为手机8",
"age": "228",
"_version_": 1617089328553394176
},
{
"id": "9",
"goodsName": "华为手机9",
"age": "229",
"_version_": 1617089328560734208
},
{
"id": "10",
"goodsName": "华为手机修改过后的值是华为2",
"age": "22",
"_version_": 1617098458274988032
}
]
}
}
查询的结果是:
Solr分页
1.新建一个bo类SolrPage
package com.wei.solr.bo;
import java.util.List;
public class SolrPage<T> {
//初始页
private Integer page = 1;
//每页大小
private Integer pageSize = 10;
//当前页
private Integer pageCount;
//总页数
private Integer pagSum;
//数据
private List<T> datas;
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getPageCount() {
return pageCount;
}
public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}
public Integer getPagSum() {
return pagSum;
}
public void setPagSum(Integer pagSum) {
this.pagSum = pagSum;
}
public List<T> getDatas() {
return datas;
}
public void setDatas(List<T> datas) {
this.datas = datas;
}
}
2.设置分页参数
方法名 | 设置的作用 |
---|---|
setStart | 从第几条开始 |
setRows | 分页取多少条 |
3.获取开始查询的位置
//从第几条开始
solrQuery.setStart((solrPage.getPage()-1)*solrPage.getPageSize());
//取多少条
solrQuery.setRows(solrPage.getPageSize());
4.获取分页总数
solrClient.query(solrQuery);
SolrDocumentList results = query.getResults();
long numFound = results.getNumFound();
5.获取当前页
solrClient.query(solrQuery);
SolrDocumentList results = query.getResults();
solrPage.setPageCount(solrPage.getPagSum() % solrPage.getPageSize() == 0 ?
solrPage.getPagSum() / solrPage.getPageSize():
solrPage.getPagSum() / solrPage.getPageSize()+1);
6.获取数据
solrClient.query(solrQuery);
SolrDocumentList results = query.getResults();
for (SolrDocument result : results) {
Goods goods = new Goods();
Integer id = Integer.parseInt(result.getFieldValue("id")+"");
if (highlighting.containsKey(id+"")) {
List<String> goodsNameList = highlighting.get(id + "").get("goodsName");
StringBuilder sb = new StringBuilder();
for (String goodsName : goodsNameList) {
sb.append(goodsName+"...");
}
goods.setGoodsName(sb.toString());
}
goods.setAge(Integer.parseInt(result.getFieldValue("age")+""));
goods.setSex((String) result.getFieldValue("sex"));
goodList.add(goods);
solrPage.setDatas(goodList);
}