课程资料包
solr搜索引擎服务器
官网
Solr is the popular, blazing-fast, open source enterprise search platform built on Apache Lucene™.
solr 安装
熟悉一下
docker-compose.yml
version: '3.1'
services:
solr:
image: solr:5.5.5
restart: always
container_name: solr_test
ports:
- 8983:8983
Dockerfile构建属于自己的Solr镜像
Dockfile
# 基于哪个镜像,如果不写版本则是最新的
# 不同版本的话要注意一下路径,下面的路径
FROM solr:5.5.5
# 作者
MAINTAINER sunofbeach.net
# 创建 Core,切换目录
WORKDIR /opt/solr/server/solr
# 创建目录
RUN mkdir sob_blog_core
# 切换目录
WORKDIR /opt/solr/server/solr/sob_blog_core
# 把这个Core名称添加到配置文件中,这样在前端就可以看到了
RUN echo 'name=sob_blog_core' > core.properties
# 从模版中复制一份出来配置文件出来
RUN cp -r /opt/solr/server/solr/configsets/sample_techproducts_configs/conf/ .
# 进入到容器的lib文件夹
WORKDIR /opt/solr/server/solr-webapp/webapp/WEB-INF/lib
# 中文分词器
RUN cp -r /opt/solr/contrib/analysis-extras/lucene-libs/lucene-analyzers-smartcn-5.5.5.jar .
# 复制两个jar包进去
ADD ik-analyzer-solr5-5.x.jar .
ADD solr-analyzer-ik-5.1.0.jar .
WORKDIR /opt/solr/server/solr-webapp/webapp/WEB-INF
# 复制字典,同学们可以自行修改字典内容
ADD ext.dic .
ADD stopword.dic .
# 配置扩展字典的配置文件
ADD IKAnalyzer.cfg.xml .
# 增加分词配置
COPY managed-schema /opt/solr/server/solr/sob_blog_core/conf
WORKDIR /opt/solr
在当文件夹下构建,相关的文件要复制到位,文件在课程压缩包里
docker build -t sob_blog_solr:1.0 .
等待构建完成,或者直接使用docker-compose构建也行
version: '3.1'
services:
solr:
build: solrWithIKAnalyzer
restart: always
container_name: sob_blog_solr
ports:
- 8983:8983
创建完成以后访问:
ip:8983
这个就是操作界面了
项目链接solr
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
</dependency>
添加链接配置项
spring:
data:
solr:
host: http://192.168.220.141:8983/solr/sob_blog_core
数据的增删改
注入SolrClient
@Autowired
private SolrClient client;
然后添加字段内容,这些字段就是我们在约束文件里配置的
<!--自定义字段,类似于设计数据表一样-->
<!--ID-->
<!--ID 已经在前面有了-->
<!--浏览量-->
<field name="blog_view_count" type="int" indexed="true" stored="true" required="true" multiValued="false" />
<!--标题-->
<field name="blog_title" type="text_cn" indexed="true" stored="true" required="true" multiValued="false" />
<!--内容-->
<field name="blog_content" type="text_cn" indexed="true" stored="true" required="true" multiValued="false" />
<!--创建时间-->
<field name="blog_create_time" type="date" indexed="true" stored="true" required="true" multiValued="false" />
<!--标签-->
<field name="blog_labels" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<!--文章链接-->
<field name="blog_url" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<!--分类ID-->
<field name="blog_category_id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<!--搜索item-->
<field name="search_item" type="text_cn" indexed="true" stored="true" required="true" multiValued="true" />
searchItem不需要添加,自动复制的,因为我们有以下配置
<copyField source="blog_title" dest="search_item"/>
<copyField source="blog_content" dest="search_item"/>
<copyField source="blog_labels" dest="search_item"/>
添加
代码编写:
创建SolrInputDocument
SolrInputDocument doc = new SolrInputDocument();
封装字段数据
doc.addField("id", id);
doc.addField("blog_view_count", 标题内容);
doc.addField("blog_title", 标题内容);
doc.addField("blog_content", 搜索内容);
doc.addField("blog_create_time", 创建时间);
doc.addField("blog_labels", 标签);
doc.addField("blog_url", 文章url);
提交
try {
client.add(doc);
client.commit();
} catch (Exception e) {
e.printStackTrace();
}
删除
前面我们设置了ID,ID是主键,所以我们可以通过ID来删除
try {
client.deleteById(articleId);
client.commit();
} catch (Exception e) {
e.printStackTrace();
}
更新
更新跟添加一样,以id为key,修改对应ID的内容,注意不可以为空的字段.
处理数据标签问题
富文本我们需要去掉Html标签,markdown我们需要转成html,再去掉里面的标签,提取纯文本内容。
markdown转成html
<!--markdown to html-->
<dependency>
<groupId>com.vladsch.flexmark</groupId>
<artifactId>flexmark-all</artifactId>
<version>0.50.44</version>
</dependency>
代码
// markdown to html
MutableDataSet options = new MutableDataSet().set(Parser.EXTENSIONS, Arrays.asList(
TablesExtension.create(),
JekyllTagExtension.create(),
TocExtension.create(),
SimTocExtension.create()
));
Parser parser = Parser.builder(options).build();
HtmlRenderer renderer = HtmlRenderer.builder(options).build();
Node document = parser.parse(内容);
String html = renderer.render(document);
html转text
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
html转文字
Jsoup.parse(html内容).text()
查询
- q:query查询
- fq:filter query 过滤查询
- sort:排序
- start,rows:分页
- fl:返回字段
- dl:默认的查询参考字段
- hl:高亮
@Override
public ResponseResult doSearch(String keyword, int page, int size, String categoryId, Integer sort) {
//1、检查page和size
page = checkPage(page);
size = checkSize(size);
SolrQuery solrQuery = new SolrQuery();
//2、分页设置
//先设置每页的数量
solrQuery.setRows(size);
//设置开始的位置
//找个规律
//第1页 -- > 0
//第2页 == > size
//第3页 == > 2*size
//第4页 == > 3*size
//第n页 == > (n-1)*size
int start = (page - 1) * size;
solrQuery.setStart(start);
//solrQuery.set("start", start);
//3、设置搜索条件
//关键字
solrQuery.set("df", "search_item");
//条件过滤
if (TextUtils.isEmpty(keyword)) {
solrQuery.set("q", "*");
} else {
solrQuery.set("q", keyword);
}
//排序
//排序有四个:根据时间的升序(1)和降序(2),根据浏览量的升序(3)和降序(4)
if (sort != null) {
if (sort == 1) {
solrQuery.setSort("blog_create_time", SolrQuery.ORDER.asc);
} else if (sort == 2) {
solrQuery.setSort("blog_create_time", SolrQuery.ORDER.desc);
} else if (sort == 3) {
solrQuery.setSort("blog_view_count", SolrQuery.ORDER.asc);
} else if (sort == 4) {
solrQuery.setSort("blog_view_count", SolrQuery.ORDER.desc);
}
}
//分类
if (!TextUtils.isEmpty(categoryId)) {
solrQuery.setFilterQueries("blog_category_id:" + categoryId);
}
//关键字高亮
solrQuery.setHighlight(true);
solrQuery.addHighlightField("blog_title,blog_content");
solrQuery.setHighlightSimplePre("<font color='red'>");
solrQuery.setHighlightSimplePost("</font>");
solrQuery.setHighlightFragsize(500);
//设置返回字段
//blog_content,blog_create_time,blog_labels,blog_url,blog_title,blog_view_count
solrQuery.addField("id,blog_content,blog_create_time,blog_labels,blog_url,blog_title,blog_view_count");
//
//4、搜索
try {
//4.1、处理搜索结果
QueryResponse result = solrClient.query(solrQuery);
//获取到高亮内容
Map<String, Map<String, List<String>>> highlighting = result.getHighlighting();
//把数据转成bean类
List<SearchResult> resultList = result.getBeans(SearchResult.class);
//结果列表
for (SearchResult item : resultList) {
Map<String, List<String>> stringListMap = highlighting.get(item.getId());
List<String> blogContent = stringListMap.get("blog_content");
if (blogContent != null) {
item.setBlogContent(blogContent.get(0));
}
List<String> blogTitle = stringListMap.get("blog_title");
if (blogTitle != null) {
item.setBlogTitle(blogTitle.get(0));
}
}
//5、返回搜索结果
//包含内容
//列表、页面、每页数量
long numFound = result.getResults().getNumFound();
PageList<SearchResult> pageList = new PageList<>(page, numFound, size);
pageList.setContents(resultList);
//返回结果
return ResponseResult.SUCCESS("搜索成功.").setData(pageList);
} catch (Exception e) {
e.printStackTrace();
}
return ResponseResult.FAILED("搜索失败,请稍后重试.");
}