简介
Elasticsearch中文文档
ELK:
ELK是Elasticsearch、Logstash、Kibana三大开源架构的字母简称
Elasticsearch是基于Lucene、分布式、通过restful方式进行交互的进实时搜索平台框架。
Logstash是ELK的中英文数据流引擎,用于从不同目标收集不同格式数据,经过过滤后支持输出到不同的目的地。
Kibana是将Elasticsearch的数据展示出来,提供实时分析的功能。
下面的例子是实现中文词汇的搜索,并高亮显示。
使用
一、安装Elasticsearch
下载后进行解压,然后双击bin目录下面的elasticsearch.bat即可启动成功,启动成功效果图:
访问上图的路径:127.0.0.1:9200
访问成功的界面如下图:
二、安装 Elasticsearch Head插件
Elasticsearch-head 是一个基于node.js的前端工程,是elasticsearch的可视化客户端工具
下载解压后如下图操作:
打开后在命令窗口依次输入
npm install
npm run start
启动成功后的界面:
访问上面的地址——http://localhost:9100
访问后发现有跨域的问题,解决方法:
修改Elasticsearch中config目录下的elasticsearch.yml文件,在最下面加上跨域的代码
三、安装IK分词器插件
分词:把一段中文或者其他语言划分成一个个关键字,在搜索的时候,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每一个字看一个词,比如将“我爱学习”,会被分成“我” “爱” “学” “习”四个字,这不符合要求,需要安装中文分词器ik来解决这个问题。
将下载解压后的文件放入到新的文件夹中命名为Ik,然后将Ik文件夹放入到Elasticsearch的plugin文件下面
重启Elasticsearch后,可以看到显示加载了Ik插件
四、代码编写
1、引入相关的pom文件
引入相关的pom文件并修改elasticsearch的版本号为下载的版本号
<properties>
<elasticsearch.version>7.10.1</elasticsearch.version>
</properties>
<!-- 导入fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- 导入elasticsearch依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2、配置类代码
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient(){
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("127.0.0.1",9200,"http")));
return client;
}
}
3、业务类代码
我写的是将数据库中的数据先拿出来,然后存入到Elasticsearch中,再进行搜索中文短语为高亮显示。
package com.tfjybj.dtc.search.service.impl;
import com.alibaba.fastjson.JSON;
import com.tfjybj.dtc.search.model.ContentModel;
import com.tfjybj.dtc.search.service.abs.AbsElasticSearch;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @version 1.0
* @Description 将数据库中的内容放入到es当中
* @Author 刘一鸣
* @CreateDate 2021/1/8 8:39
* @UpdateUser
* @UpdateDate
* @UpdateRemark
*/
@Service
public class ElasticSearchImpl extends AbsElasticSearch {
@Autowired
private RestHighLevelClient restHighLevelClient;
@Autowired
private GlobalSearchImpl globalSearch;
public List<String> parseContent() throws IOException {
/**
* @Describe 1、将数据库中所有数据都拿出来
* @Author 刘一鸣
* @Date 2021/1/9 8:51
* @param
* @Return java.util.List<java.lang.String>
*/
List<String> contentList = globalSearch.queryAll();
List<ContentModel> contentModelList = new ArrayList<>();
for (int i = 0; i < contentList.size(); i++) {
ContentModel contentModel = new ContentModel();
contentModel.setContents(contentList.get(i));
contentModelList.add(contentModel);
}
System.out.println(contentModelList);
/**
* @Describe 2、将从数据库拿出来的数据存入到es索引当中
* @Author 刘一鸣
* @Date 2021/1/9 8:52
* @param []
* @Return java.util.List<java.lang.String>
*/
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("2m");
for (int i = 0; i < contentList.size(); i++) {
bulkRequest.add(
new IndexRequest("dtc_content")
.source(JSON.toJSONString(contentModelList.get(i)), XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return contentList;
}
/**
* @param keyword, pageNo, pageSize
* @Describe 3、获取这些数据实现搜索高亮
* @Author 刘一鸣
* @Date 2021/1/9 8:52
* @Return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
*/
public List<Map<String, Object>> searchPageHighlight(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest("dtc_content");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
// 精准匹配(支持中文词语搜索)
sourceBuilder.query(QueryBuilders.boolQuery().should(QueryBuilders.matchPhraseQuery("contents", keyword)));
//QueryBuilders.boolQuery()
// .should(QueryBuilders.matchQuery("contents",keyword)
// .analyzer("ik_max_word")
// .operator(Operator.OR));
//TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("contents",keyword);
//sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
// 高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("contents");
// 关闭多个高亮显示
highlightBuilder.requireFieldMatch(false);
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
sourceBuilder.highlighter(highlightBuilder);
// 执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 解析结果
ArrayList<Map<String, Object>> list = new ArrayList<>();
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
HighlightField title = highlightFields.get("contents");
//原来的结果
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
//解析高亮的字段,将原来的字段换成我们高亮的字段即可
if (title != null) {
org.elasticsearch.common.text.Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
//将高亮替换为原来的内容
sourceAsMap.put("contents", n_title);
}
list.add(sourceAsMap);
}
return list;
}
}
4、model类代码
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ContentModel {
private String contents;
}
5、controller类代码
/**
* @Describe 高亮显示
* @Author 刘一鸣
* @Date 2021/1/9 8:56
* @param keyword, pageNo, pageSize
* @Return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
*/
@ApiOperation(value = "查询es索引中的内容并高亮显示")
@GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
public List<Map<String,Object>> search(@PathVariable("keyword") String keyword,
@PathVariable("pageNo") int pageNo,
@PathVariable("pageSize") int pageSize) throws IOException {
return elasticSearch.searchPageHighlight(keyword,pageNo,pageSize);
}
6、前端书写
书写好前端的样式后,前端调后端的search接口即可。
这里重点写一下v-html在element-ui组件中el-table表格中的用法
<el-table :data="results">
<el-table-column prop="contents">
<template slot-scope="scope">
<div v-html="scope.row.contents"></div>
</template>
</el-table-column>
</el-table>