Elasticsearch 分词

分词分为读时分词和写时分词。
读时分词发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失。而写时分词发生在文档写入时,ES 会对文档进行分词后,将结果存入倒排索引,该部分最终会以文件的形式存储于磁盘上,不会因查询结束或者 ES 重启而丢失。
写时分词器需要在 mapping 中指定,而且一经指定就不能再修改,若要修改必须新建索引。

分词一般在ES中有分词器处理。英文为Analyzer,它决定了分词的规则,Es默认自带了很多分词器,如:
Standard、english、Keyword、Whitespace等等。默认的分词器为Standard,通过它们各自的功能可组合
成你想要的分词规则。分词器具体详情可查看官网:分词器
另外,在常用的中文分词器、拼音分词器、繁简体转换插件。国内用的就多的分别是:
elasticsearch-analysis-ik
elasticsearch-analysis-pinyin
elasticsearch-analysis-stconvert
可在以上链接找到自己对于的elasticsearch版本安装插件。
这里提供一个我自己封装的elasticsearch 5.5.0 的Docker镜像,里面在官方镜像的基础上加入了以上三个个插件,链接:
liaodashuai/elasticsearch:1.0.2

简单了解至此,下面用SpringBoot 集成
实现:

打造匹配搜索和高亮搜索API
使用中文、拼音和繁简体都能搜索到
扩展另外众多的搜索方式,简单使用测试用例实现

集成SpringBoot 实现高亮显示、拼音搜索

  1. 导入jar包,springboot 2.0.4只支持5.X版本的Es,注意版本对应,避免坑。
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-elasticsearch', version: '2.0.6.RELEASE'compile 'org.elasticsearch.client:x-pack-transport:5.5.0'
  1. 配置连接Es
@Configuration
public class EsConfiguration {private Client esClient;/*** Transport client transport client.* 如果配置X-PACK ,则需要在此处配置用户信息** @return the transport client*/@Beanpublic Client transportClient() {TransportClient client = null;try {client = new PreBuiltXPackTransportClient(Settings.builder()//嗅探集群状态
//                    .put("client.transport.sniff", true).put("cluster.name", "docker-cluster")//如果有配置xpack插件,需要配置登录.put("xpack.security.user", "elastic:changeme").build()).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("120.79.58.138"), 9300));} catch (UnknownHostException e) {log.error("elasticsearch 连接失败 !");}return client;}/*** 避免TransportClient每次使用创建和释放*/public Client esTemplate() {if (StringUtils.isEmpty(esClient) || StringUtils.isEmpty(esClient.admin())) {esClient = transportClient();return esClient;}return esClient;}
}
  1. 配置实体Mapping
@Document(indexName = "film-entity", type = "film")
@Setting(settingPath = "/json/film-setting.json")
@Mapping(mappingPath = "/json/film-mapping.json")
public class FilmEntity {@Idprivate Long id;
//    @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_smart")private String name;private String nameOri;private String publishDate;private String type;private String language;private String fileDuration;private String director;
//    @Field(type = FieldType.Date)private Date created ;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getNameOri() {return nameOri;}public void setNameOri(String nameOri) {this.nameOri = nameOri;}public String getPublishDate() {return publishDate;}public void setPublishDate(String publishDate) {this.publishDate = publishDate;}public String getType() {return type;}public void setType(String type) {this.type = type;}public String getLanguage() {return language;}public void setLanguage(String language) {this.language = language;}public String getFileDuration() {return fileDuration;}public void setFileDuration(String fileDuration) {this.fileDuration = fileDuration;}public String getDirector() {return director;}public void setDirector(String director) {this.director = director;}public Date getCreated() {return created;}public void setCreated(Date created) {this.created = created;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}@Overridepublic String toString() {return "FilmEntity [id=" + id + ", name=" + name + ", director=" + director + "]";}
}

上面的Model有必要解释一下,SpringBoot 有为我们提供多种方式设置mapping,你可以按喜好选择使用,我选择
的使用@Mapping注解配置,使用es原生的方式进行设置,虽然有点小麻烦,但是更加直观了,也不仅限于java,也可以直接用curl或es控制台创建。
film-mapping.json

{"film": {"_all": {"enabled": true},"properties": {"id": {"type": "integer"},"name": {"type": "text","analyzer": "ikSearchAnalyzer","search_analyzer": "ikSearchAnalyzer","fields": {"pinyin": {"type": "text","analyzer": "pinyinSimpleIndexAnalyzer","search_analyzer": "pinyinSimpleIndexAnalyzer"}}},"nameOri": {"type": "text"},"publishDate": {"type": "text"},"type": {"type": "text"},"language": {"type": "text"},"fileDuration": {"type": "text"},"director": {"type": "text","index": "true","analyzer": "ikSearchAnalyzer"},"created": {"type": "date","format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"}}}
}

另外,除了@Mapping,SpringBoot还为我们提供了另一强大的注解@Setting,该注解可以让我们为当前索引设置一些相关属性,相当于
elasticsearch中的settings配置,例如:
film-setting.json

{"index": {"analysis": {"filter": {"edge_ngram_filter": {"type": "edge_ngram","min_gram": 1,"max_gram": 50},"pinyin_simple_filter": {"type": "pinyin","first_letter": "prefix","padding_char": " ","limit_first_letter_length": 50,"lowercase": true}},"char_filter": {"tsconvert": {"type": "stconvert","convert_type": "t2s"}},"analyzer": {"ikSearchAnalyzer": {"type": "custom","tokenizer": "ik_max_word","char_filter": ["tsconvert"]},"pinyinSimpleIndexAnalyzer": {"tokenizer": "keyword","filter": ["pinyin_simple_filter","edge_ngram_filter","lowercase"]}}}}
}

上面的JSON作用是创建两个分析器名为ikSearchAnalyzer,pinyinSimpleIndexAnalyzer,前者使用ik中文分词器加繁体转简体char_filter过滤,使得引用此分词器的字段在设置时,将会自动对中文进行分词和繁简体转换。
pinyinSimpleIndexAnalyzer 使用pinyin分词器,并进行edge_ngram 过滤,大写转小写过滤。
上述设置完后,启动应用,打开head插件,也可以使用google扩展,elasticsearch-head。

创建好索引后,便可开始测试查询了。
使用SpringBoot提供的ElasticsearchRepository<T,ID>构建简单查询,当然它也是有局限的,一些较复杂的查询,只能通过
SearchResponse 自定义设置。
首先我们实现简单的普通查询,可以配合Repository,继承ElasticsearchRepository<T,ID>,简单的CRUD都提供了。

public interface FilmDao extends ElasticsearchRepository<FilmEntity, Long> {}

先创建几条测试数据:

service类,构建查询

    /*** 拼接搜索条件** @param name     the name* @param director the director* @return list*/public List<FilmEntity> search(String name, String director) {//使用中文拼音混合搜索,取分数最高的,具体评分规则可参照://  https://blog.csdn.net/paditang/article/details/79098830SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(structureQuery(name)).build();List<FilmEntity> list = filmDao.search(searchQuery).getContent();return list;}/*** 中文、拼音混合搜索** @param content the content* @return dis max query builder*/public DisMaxQueryBuilder structureQuery(String content) {//使用dis_max直接取多个query中,分数最高的那一个query的分数即可DisMaxQueryBuilder disMaxQueryBuilder = QueryBuilders.disMaxQuery();//boost 设置权重,只搜索匹配name和disrector字段QueryBuilder ikNameQuery = QueryBuilders.matchQuery("name", content).boost(2f);QueryBuilder pinyinNameQuery = QueryBuilders.matchQuery("name.pinyin", content);QueryBuilder ikDirectorQuery = QueryBuilders.matchQuery("director", content).boost(2f);disMaxQueryBuilder.add(ikNameQuery);disMaxQueryBuilder.add(pinyinNameQuery);disMaxQueryBuilder.add(ikDirectorQuery);return disMaxQueryBuilder;}

输入拼音搜索“ceshi”可看到对应结果,当然中文也是可以的:

输入简体字搜索"测试",可看到对应结果

service类,构建高亮查询

 public List<FilmEntity> search(String query) {Client client = esConfig.esTemplate();HighlightBuilder highlightBuilder = new HighlightBuilder();//高亮显示规则highlightBuilder.preTags("<span style='color:green'>");highlightBuilder.postTags("</span>");//指定高亮字段highlightBuilder.field("name");highlightBuilder.field("name.pinyin");highlightBuilder.field("director");String[] fileds = {"name", "name.pinyin", "director"};QueryBuilder matchQuery = QueryBuilders.multiMatchQuery(query, fileds);//搜索数据SearchResponse response = client.prepareSearch("film-entity").setQuery(matchQuery).highlighter(highlightBuilder).execute().actionGet();SearchHits searchHits = response.getHits();System.out.println("记录数-->" + searchHits.getTotalHits());List<FilmEntity> list = new ArrayList<>();for (SearchHit hit : searchHits) {FilmEntity entity = new FilmEntity();Map<String, Object> entityMap = hit.getSourceAsMap();System.out.println(hit.getHighlightFields());//高亮字段if (!StringUtils.isEmpty(hit.getHighlightFields().get("name"))) {Text[] text = hit.getHighlightFields().get("name").getFragments();entity.setName(text[0].toString());entity.setDirector(String.valueOf(entityMap.get("director")));}if (!StringUtils.isEmpty(hit.getHighlightFields().get("name.pinyin"))) {Text[] text = hit.getHighlightFields().get("name.pinyin").getFragments();entity.setName(text[0].toString());entity.setDirector(String.valueOf(entityMap.get("director")));}if (!StringUtils.isEmpty(hit.getHighlightFields().get("director"))) {Text[] text = hit.getHighlightFields().get("director").getFragments();entity.setDirector(text[0].toString());entity.setName(String.valueOf(entityMap.get("name")));}//map to objectif (!CollectionUtils.isEmpty(entityMap)) {if (!StringUtils.isEmpty(entityMap.get("id"))) {entity.setId(Long.valueOf(String.valueOf(entityMap.get("id"))));}if (!StringUtils.isEmpty(entityMap.get("language"))) {entity.setLanguage(String.valueOf(entityMap.get("language")));}}list.add(entity);}return list;
}

上面配置了高亮搜索字段[name,name.pinyin,director],也就是说匹配到这三个字段的高亮结果,则会加上自定义的
高亮显示规则:

<span style='color:green'>...</span>

输入拼音搜索“ceshi”可看到对应结果,当然中文也是可以的:

输入简体字搜索"测试",可看到对应结果

输入繁体字搜索"認爲",可看到对应结果,由于pinyin分词器影响还会取到小王。

实际上有搜索到有多个高亮结果的,这里只取第一个演示查看。

大家肯定很好奇这分词到底是怎么分的,为此我专门提供一个接口,可以查看我们输入的搜索内容是怎样被分词的。
api测试:

结果如下:

{"result": [{"term": "xiao","startOffset": 0,"endOffset": 2,"position": 0,"positionLength": 1,"attributes": null,"type": "CN_WORD","fragment": false},{"term": "xm","startOffset": 0,"endOffset": 2,"position": 0,"positionLength": 1,"attributes": null,"type": "CN_WORD","fragment": false},{"term": "ming","startOffset": 0,"endOffset": 2,"position": 1,"positionLength": 1,"attributes": null,"type": "CN_WORD","fragment": false}],"msg": "","code": 200,"is_success": true
}

可以看到,我们的分词器已经生效。

以上示例源码以上传至GitHub:https://github.com/liaozihong/SpringBoot-Learning/tree/master/SpringBoot-Elasticsearch-Query

参考链接:
Elasticsearch 分词检索
Java API 5.5.0
Elasticsearch 结合SpringBoot 高亮显示查询

SpringBoot集成Elasticsearch 进阶,实现中文、拼音分词,繁简体转换高级搜索相关推荐

  1. springboot集成elasticsearch,实现搜索提示补全功能

    springboot集成elasticsearch,通过实体类创建索引,实现搜索提示补全功能 文章目录 springboot集成elasticsearch,通过实体类创建索引,实现搜索提示补全功能 一 ...

  2. es拼音分词 大帅哥_SpringBoot集成Elasticsearch 进阶,实现中文、拼音分词,繁简体转换...

    Elasticsearch 分词 分词分为读时分词和写时分词. 读时分词发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失.而写时分词 ...

  3. Springboot集成elasticsearch 使用IK+拼音分词

    Springboot集成elasticsearch 使用IK+拼音分词 docker安装ES 下载 docker pull docker.elastic.co/elasticsearch/elasti ...

  4. springboot集成Elasticsearch实现各种搜索功能

    springboot集成Elasticsearch各类搜索功能实现 springboot集成Elasticsearch使用completion suggest实现自动关键字补全 建立学生的索引和映射: ...

  5. 记一次springboot2.3.*项目整合elasticsearch7.6.2实现中文拼音分词搜索

    一.elasticsearch官网下载:Elasticsearch 7.6.2 | Elastic 二.拼音.ik.繁简体转换插件安装 ik分词:GitHub - medcl/elasticsearc ...

  6. 【SpringBoot高级篇】SpringBoot集成Elasticsearch搜索引擎

    [SpringBoot高级篇]SpringBoot集成Elasticsearch搜索引擎 1. 什么是Elasticsearch? 2. 安装并运行Elasticsearch 2.1 拉取镜像 2.2 ...

  7. debian 10 buster 安装配置 elastic search 和 中文, 拼音分词

    debian 10 buster 安装配置 es 和 中文, 拼音分词 安装 测试 配置 分词 IK 分词器 拼音分词 一个完整的动态映射模板(包含geo, pinyin, IK) 安装 1, 安装j ...

  8. 自学笔记-SpringBoot集成ElasticSearch

    目录 一.ElasticSearch介绍: 二.ElasticSearch安装: 三.Kibana的安装 四.配置ik分词器 五.Springboot集成ElasticSearch Ⅰ.依赖 Ⅱ.配置 ...

  9. springboot集成swagger2多模块中文配置详细步骤,解决集成mybatis或mybatis-plus无法正常使用问题

    springboot集成swagger2多模块中文配置详细步骤,解决集成mybatis或mybatis-plus无法正常使用问题 参考文章: (1)springboot集成swagger2多模块中文配 ...

  10. 史上最简单的Elasticsearch教程:SpringBoot集成Elasticsearch 实时流量监测平台

    SpringBoot集成Elasticsearch 实时流量监测平台 目录: 第一章:初尝 Elasticsearch 第二章:玩转 Kibana 第三章:开发原生 Elasticsearch 案例 ...

最新文章

  1. python高级网络编程_python高级编程——网络编程(二)
  2. 让隔壁同事哇塞的IDEA主题!
  3. 网工路由基础(6)BGP协议
  4. 5月16日亮相!华硕ZenFone 6新旗舰曝光:无刘海全面屏加持
  5. priority_quenue
  6. 51nod-1065:最小正子段和
  7. 基于matlab的模糊控制器的设计与仿真,基于MATLAB的模糊控制洗衣机的设与仿真详解.doc...
  8. Vue人资中台--打包上线
  9. 如何用python的turtle画五角星_使用Python的turtle模块画五角星
  10. Windows 技术篇 - win10系统更新后切换应用一直自动切换为微软输入法解决方法,win10微软输入法卸载方法
  11. 服务器防火墙部分指令
  12. 移动用户体验设计:iOS APP体验设计
  13. Html中文本域中加图片,如何在文本框中加图片
  14. “大多数”餐馆收银系统被用于盗用信用卡信息的恶意软件感染
  15. Python 编程辅助工具--ipython
  16. 亚马逊发多款新品:智能眼镜来了 没摄像头支持语音
  17. 使用bat脚本运行jar程序 cmd下解决乱码问题
  18. 小度机器人小胖机器人_小度机器人怎么升级?智能机器人百小度快速升级全攻略[多图]...
  19. 3.1 随机抽样函数sample()
  20. Spring Security是什么?(一)

热门文章

  1. flex:1是什么意思
  2. 年轻人如何去有效的学习(很好的鸡汤,一语惊醒梦中人)
  3. MyEclipse配置jdk
  4. Mathtype(2),用于创建此对象的程序是 Equation。您的计算机尚未安装此程序或此程序无响应。
  5. windows系统设置定时开关机的方法
  6. 构建者模式和抽象工厂模式的结合使用
  7. java中成员变量和局部变量的区别
  8. 汽车故障诊断方法及注意事项
  9. android 自定义控件github,GitHub - swordman20/AndroidDIYWidget: Android组合自定义控件
  10. mac电脑重装系统操作步骤