首页 > 其他分享 >ElasticSearch 拼音分词和自动补全

ElasticSearch 拼音分词和自动补全

时间:2023-10-22 15:22:05浏览次数:30  
标签:补全 suggest analyzer elasticsearch org import type 分词 ElasticSearch

在搜索过程中,大部分情况下会有智能提示功能,也就是开头匹配的自动补全功能,这就需要用到 ElasticSearch 的 Suggest 查询功能。用户也可能输入拼音或者查询关键字的首字母简写,比如我想查询华为手机,我可以输入 hwsj 进行查询,这就需要用到拼音分词器。本篇博客将介绍如何安装拼音分词器,以及如何进行 Suggest 查询实现自动补全功能。博客最后提供源代码下载。


一、安装拼音分词器

拼音分词器的下载地址为:https://github.com/medcl/elasticsearch-analysis-pinyin/releases

由于我使用的 ElasticSearch 的版本是 8.8.2 ,所以我随便找了一个 8 版本中最高的版本(8.9.2)进行下载。

下载完成后进行解压,发现其实是拼音分词器的源代码,需要使用 IDEA 打开源代码,然后修改其 pom 文件的配置:

将 pom 文件中 properties 下的 elasticsearch.version 配置修改为 8.8.2 即可,如下所示:

<properties>
    <elasticsearch.version>8.8.2</elasticsearch.version>
</properties>

使用 IDEA 的 Maven 进行 Clean 和 Package 打包,然后在其 targart 下的 releases 目录下就能够找到 elasticsearch-analysis-pinyin-8.8.2.zip 压缩包,该压缩包里面只有 3 个文件,将其解压到一个文件夹中,比如将文件夹的名称取名为 pinyin 然后上传到 ElasticSearch 的 plugins 目录,最后重启 ElasticSearch 即可。

需要注意的是:上面修改的 elasticsearch.version 版本最高跟自己使用的 ElasticSearch 版本一致,否则可能会造成 ElasticSearch 无法启动。

最后就是验证一下拼音分词器的安装是否成功,在 Kibana 上输入以下 DSL 语句进行词条分析测试:

POST /_analyze
{
  "text": ["北京"],
  "analyzer": "pinyin"
}

如果能够得到以下查询结果,就表明拼音分词器已经安装成功:

{
  "tokens": [
    {
      "token": "bei",
      "start_offset": 0,
      "end_offset": 0,
      "type": "word",
      "position": 0
    },
    {
      "token": "bj",
      "start_offset": 0,
      "end_offset": 0,
      "type": "word",
      "position": 0
    },
    {
      "token": "jing",
      "start_offset": 0,
      "end_offset": 0,
      "type": "word",
      "position": 1
    }
  ]
}

二、自动补全查询

ElasticSearch 提供自动补全查询功能,也就是匹配以用户输入内容开头的词条并返回,但是有一个限制:参与查询的字段必须是 completion 类型。通常情况下我们会将 completion 类型的字段内容,存储为数组,这样可以更加灵活并提高查询效率。

搭建一个 SpringBoot 工程,结构如下所示:

image

由于本篇博客的 Demo 是在上篇博客的基础上进行了简单改造,大部分内容与上篇博客的 Demo 是相同的,因此这里只介绍差异内容。

最主要的内容是 SuggestTest 类中的测试方法,具体细节如下:

package com.jobs;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
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.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.ResourceUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

@SpringBootTest
public class SuggestTest {

    @Autowired
    private RestHighLevelClient client;

    //删除之前的 myhotel 索引库
    @Test
    void deleteIndexTest() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("myhotel");
        client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println("删除索引库成功");
    }

    //重新创建 myhotel 创建索引库
    @Test
    void createIndexTest() throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("myhotel");
        //读取 resourses/JSON/CreateMyHotelJson.txt 文件内容
        File file = ResourceUtils.getFile("classpath:JSON/CreateMyHotelJson.txt");
        String createJson;
        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            createJson = br.readLine();
        }
        createIndexRequest.source(createJson, XContentType.JSON);
        client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
    }

    //重新批量添加样例数据
    //BulkRequest 可以添加各种请求,如 IndexRequest,UpdateRequest,DeleteRequest
    @Test
    void bulkRequestTest() throws IOException {
        //读取 resourses/JSON/DemoJsonData.txt 文件内容
        File file = ResourceUtils.getFile("classpath:JSON/DemoJsonData.txt");
        //使用 BulkRequest 批量请求对象
        BulkRequest request = new BulkRequest();
        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            String json = br.readLine();
            JSONObject jsonObj;
            while (StringUtils.isNotBlank(json)) {
                jsonObj = JSON.parseObject(json);
                //为 BulkRequest 添加请求对象
                request.add(new IndexRequest("myhotel")
                        .id(jsonObj.getString("id"))
                        .source(json, XContentType.JSON));
                json = br.readLine();
            }
        }
        client.bulk(request, RequestOptions.DEFAULT);
    }

    //根据字母或汉字,查询出最多 10 条自动补全信息
    @Test
    void testSuggest() throws IOException {
        SearchRequest request = new SearchRequest("myhotel");
        request.source().suggest(new SuggestBuilder().addSuggestion("mySuggest",
                //指定要查询的 es 中的字段是 suggestion,注意:字段必须是 completion 类型
                SuggestBuilders.completionSuggestion("suggestion")
                        //指定要查询的关键字,去除重复内容,以及最多返回多少条记录
                        .prefix("hy").size(10).skipDuplicates(true)));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析返回的内容
        Suggest suggest = response.getSuggest();
        CompletionSuggestion suggestion = suggest.getSuggestion("mySuggest");
        //获取 options 中的 text 内容
        List<CompletionSuggestion.Entry.Option> options = suggestion.getOptions();
        for (CompletionSuggestion.Entry.Option option : options) {
            String str = option.getText().toString();
            System.out.println(str);
        }
    }
}

由于 ElasticSearch 无法更改索引库结构,因此之前的示例索引库 myhotel 需要删除后重新创建,DSL 语句如下:

PUT /myhotel
{
  "settings": {
    "analysis": {
      "analyzer": {
        "query_anlyzer": {
          "tokenizer": "ik_max_word",
          "filter": "mypinyin"
        },
        "suggest_analyzer": {
          "tokenizer": "keyword",
          "filter": "mypinyin"
        }
      },
      "filter": {
        "mypinyin": {
          "type": "pinyin",
          "keep_full_pinyin": false,
          "keep_joined_full_pinyin": true,
          "keep_original": true,
          "limit_first_letter_length": 10,
          "remove_duplicated_term": true,
          "none_chinese_pinyin_tokenize": false
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "query_anlyzer",
        "search_analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword"
      },
      "location":{
        "type": "geo_point"
      },
      "all":{
        "type": "text",
        "analyzer": "query_anlyzer",
        "search_analyzer": "ik_max_word"
      },
      "suggestion":{
          "type": "completion",
          "analyzer": "suggest_analyzer"
      }
    }
  }
}

这里自定义了 2 个分词器,分别是 query_anlyzer 和 suggest_analyzer,对于查询的字段使用 query_anlyzer,对于自动补全的字段使用 suggest_analyzer。可以发现新创建的 myhotel 索引库,新增加了一个字段 suggestion 其字段类型为 completion 。

在 SuggestTest 类中重新给 myhotel 索引库批量添加文档数据,其中给文档的 suggestion 字段添加的内容是由名称和品牌组成的数组,这样在自动补全提示时,可以直接显示出名称或者品牌。

在 SuggestTest 类中的 testSuggest 测试方法,就是自动补全的测试代码,其中 prefix 内容就是需要传入的查询内容。


本篇博客的 Demo 相对比较简单,具体代码已经测试无误,可以下载源代码进行测试验证。

源代码下载地址为:https://files.cnblogs.com/files/blogs/699532/springboot_suggest.zip

标签:补全,suggest,analyzer,elasticsearch,org,import,type,分词,ElasticSearch
From: https://www.cnblogs.com/studyjobs/p/17780482.html

相关文章

  • Elasticsearch的架构
    1.3Elasticsearch的架构Gateway层es用来存储索引文件的一个文件系统且它支持很多类型,例如:本地磁盘、共享存储(做snapshot的时候需要用到)、hadoop的hdfs分布式存储、亚马逊的S3。它的主要职责是用来对数据进行长持久化以及整个集群重启之后可以通过gateway重新恢复数据。Distributed......
  • Java 实现结巴分词
    pom.xml引入结巴分词maven依赖<dependency> <groupId>com.huaban</groupId> <artifactId>jieba-analysis</artifactId> <version>1.0.2</version></dependency>测试@Testpublicvoidtest(){StringgoodsNa......
  • 使用docker命令行为elasticsearch安装ik中文分词插件
    背景:mac+dockerdesktop+elasticsearch7.8.0 一、安装ik中文分词插件dockerexec-itelastic_search/bin/bash-c'bin/elasticsearch-plugininstallhttps://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.0/elasticsearch-analysis-ik-7.8.0......
  • elasticsearch 设置高亮
    1、引入配置springboot环境<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version></parent>引入es配置<!--e......
  • Elasticsearch 7.17.7开启x-pack
    1、ES配置文件  elasticsearch.ymlcluster.name:elasticsearchnode.name:node-1network.host:0.0.0.0discovery.type:single-nodexpack.security.enabled:truexpack.security.authc.api_key.enabled:true设置密码/usr/share/elasticsearch/bin/elasticsearch-s......
  • elasticsearch 8.7.0的Java API详解教程(一)
    最近作者做一个es的搜索,之前采用的是7.12.1,本来接口都已经基本上写好了,后面es要升级到8.7.0,一升级就连接不上es8.7.0了,后面才发现原来es8是默认采用了HTTPS协议,需要配置认证证书,这个问题搞了好久好久,最后终于搞成功了,在此写一篇博客记录一下。一、pom文件<?xmlversion="1.0"encod......
  • Elasticsearch(ES):现代搜索与分析引擎
    大数据时代带来了海量的信息和数据,如何高效地管理、搜索和分析这些数据成为了企业和组织面临的重要挑战。在这个背景下,Elasticsearch应运而生,它是一款强大的开源搜索和分析引擎,广泛用于各种领域,从企业搜索、日志分析到监控系统,为用户提供了快速、准确的数据搜索和分析功能。1.什么......
  • ElasticSearch Java API 基本操作
    前言ElasticSearchJavaAPI是ES官方在8.x版本推出的新javaapi,也可以适用于7.17.x版本的es。本文主要参考了相关博文,自己手动编写了下相关操作代码,包括更新mappings等操作的java代码。代码示例已上传github。版本elasticsearch版本:7.17.9,修改/elasticsearch-7.17.9/config/......
  • docker安装elasticsearch:8.9.0的过程
    环境是CentOS7,elasticsearch:8.9.0。使用的是root用户首先创建挂载的目录,并且赋予777权限。第一步获取elasticsearch镜像dockerpullelasticsearch 第二步 查看镜像是否下载成功dockerimages 第三步宿主机上创建用到的挂载文件 cd/optmkdir/es_docker......
  • docker部署elasticsearch 遇到FileSystemException 报错
    Exceptioninthread"main"java.nio.file.:/usr/share/elasticsearch/config/elasticsearch.yml.vxt5sWMES_eRFvPQPfckLQ.tmp->/usr/share/elasticsearch/config/elasticsearch.yml:Deviceorresourcebusy atjava.base/sun.nio.fs.UnixException.trans......