ElasticSearch自定义pinyin和ik分词库

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: ElasticSearch自定义pinyin和ik分词库

1 语料库映射OpenAPI

环境准备:

  1. 先下载ik分词和pinyin分词,并放到esplugins相应目录中

请求kibana:GET /_cat/plugins?v&s=component&h=name,component,version,description

结果

name            component   version description
WIN-A5KARTU1A65 analysis-ik 7.10.1  IK Analyzer for Elasticsearch
WPhvS8c analysis-pinyin    7.10.1   Pinyin Analysis for Elasticsearch
  1. 定义ik分词后的pinyin分词器,即定义一个自定义分词器ik_pinyin_analyzer
PUT test_index
{
  "settings":{
    "number_of_shards":"1",
    "index.refresh_interval":"15s",
    "index":{
      "analysis":{
        "analyzer":{
           "ik_pinyin_analyzer":{
            "type":"custom",
            "tokenizer":"ik_smart",
            "filter":"pinyin_filter"
          }
        },
        "filter":{
          "pinyin_filter":{
            "type":"pinyin",
            "keep_first_letter": false
          }
        }
      }
    }
  }
}

下面的目的就是用API实现这种效果

这里tokenizer使用ik分词,分词之后将分词结果通过pinyin再filter一次,这样就可以了。

测试一下

POST test_index/_analyze
{
  "analyzer": "ik_pinyin_analyzer",
  "text":"测试"
}

结果

{
  "tokens": [
    {
      "token": "ce",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 0
    },
    {
      "token": "shi",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 1
    }
  ]
}

这样,当我们建立index的mapping的时候,就可以像使用ik_smart分词器一样使用ik_pinyin_analyzer

比如lawbasis字段的mapping可以是这样的

PUT test_index/_mapping/test_type
{
  "properties": {
    "lawbasis":{
      "type": "text",
      "analyzer": "ik_smart",
      "search_analyzer": "ik_smart",
      "fields": {
        "my_pinyin":{
          "type":"text",
          "analyzer": "ik_pinyin_analyzer",
          "search_analyzer": "ik_pinyin_analyzer"
        }
      }
    }
  }
}

其中field满足以不同的目的以不同的方式为相同的字段编制索引,也就是说lawbasis这个field会以中文ik_smart分词以及分词后的pinyin分词来编制索引,并支持中文和拼音搜索。

  1. 测试一下

加入两条数据

POST test_index/test_type
{
  "lawbasis":"测试一下"
}
POST test_index/test_type
{
  "lawbasis":"测试东西"
}

使用拼音搜索

GET test_index/test_type/_search
{
  "query":{
    "match": {
      "lawbasis.my_pinyin": "ceshi"
    }
  }
}

可以看到有两条结果

1.1 定义索引(映射)接口

package com.oldlu.service;
import com.oldlu.commons.pojo.CommonEntity;
import org.elasticsearch.rest.RestStatus;
import java.util.List;
import java.util.Map;
/**
* @Class: ElasticsearchIndexService
* @Package com.oldlu.service
* @Description: 索引操作接口
* @Company: oldlu
*/
public interface ElasticsearchIndexService {
  //新增索引+映射
  boolean addIndexAndMapping(CommonEntity commonEntity) throws Exception;
}

1.2 定义索引(映射)实现

/**
* @Class: ElasticsearchIndexServiceImpl
* @Package com.oldlu.service.impl
* @Description: 索引操作实现类
* @Company: oldlu
*/
@Service("ElasticsearchIndexServiceImpl")
public class ElasticsearchIndexServiceImpl implements ElasticsearchIndexService
{
  @Resource
  private RestHighLevelClient client;
  private static final int START_OFFSET = 0;
  private static final int MAX_COUNT = 5;
  /*
  * @Description: 新增索引+setting+映射+自定义分词器pinyin
  * setting可以为空(自定义分词器pinyin在setting中)
  * 映射可以为空
  * @Method: addIndexAndMapping
  * @Param: [commonEntity]
  * @Update:
  * @since: 1.0.0
  * @Return: boolean
  *
  */
 public boolean addIndexAndMapping(CommonEntity commonEntity) throws
Exception {
    //设置setting的map
    Map<String, Object> settingMap = new HashMap<String, Object>();
    //创建索引请求
    CreateIndexRequest request = new
CreateIndexRequest(commonEntity.getIndexName());
    //获取前端参数
    Map<String, Object> map = commonEntity.getMap();
    //循环外层的settings和mapping
    for (Map.Entry<String, Object> entry : map.entrySet()) {
      if ("settings".equals(entry.getKey())) {
        if (entry.getValue() instanceof Map && ((Map)
entry.getValue()).size() > 0) {
          request.settings((Map<String, Object>) entry.getValue());
       }
     }
      if ("mapping".equals(entry.getKey())) {
        if (entry.getValue() instanceof Map && ((Map)
entry.getValue()).size() > 0) {
          request.mapping((Map<String, Object>) entry.getValue());
       }
     }
   }
    //创建索引操作客户端
    IndicesClient indices = client.indices();
    //创建响应对象
    CreateIndexResponse response = indices.create(request,
RequestOptions.DEFAULT);
    //得到响应结果
    return response.isAcknowledged();
 }
}

1.3 新增控制器

package com.oldlu.controller;
import com.oldlu.commons.enums.ResultEnum;
import com.oldlu.commons.enums.TipsEnum;
import com.oldlu.commons.pojo.CommonEntity;
import com.oldlu.commons.result.ResponseData;
import com.oldlu.service.ElasticsearchIndexService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @Class: ElasticsearchIndexController
* @Package com.oldlu.controller
* @Description: 索引操作控制器
* @Company: oldlu
*/
@RestController
@RequestMapping("v1/indices")
public class ElasticsearchIndexController {
  private static final Logger logger = LoggerFactory
     .getLogger(ElasticsearchIndexController.class);
  @Autowired
  ElasticsearchIndexService elasticsearchIndexService;
  /*
  * @Description: 新增索引、映射
  * @Method: addIndex
  * @Param: [commonEntity]
  * @Update:
  * @since: 1.0.0
  * @Return: com.oldlu.commons.result.ResponseData
  *
  */
  @PostMapping(value = "/add")
  public ResponseData addIndexAndMapping(@RequestBody CommonEntity
commonEntity) {
    //构造返回数据
    ResponseData rData = new ResponseData();
    if (StringUtils.isEmpty(commonEntity.getIndexName())) {
      rData.setResultEnum(ResultEnum.PARAM_ISNULL);
      return rData;
   }
    //增加索引是否成功
    boolean isSuccess = false;
    try {
      //通过高阶API调用增加索引方法
      isSuccess =
elasticsearchIndexService.addIndexAndMapping(commonEntity );
      //构建返回信息通过类型推断自动装箱(多个参数取交集)
      rData.setResultEnum(isSuccess, ResultEnum.SUCCESS, 1);
      //日志记录
      logger.info(TipsEnum.CREATE_INDEX_SUCCESS.getMessage());
   } catch (Exception e) {
      //日志记录
      logger.error(TipsEnum.CREATE_INDEX_FAIL.getMessage(), e);
      //构建错误返回信息
      rData.setResultEnum(ResultEnum.ERROR);
   }
    return rData;
 }
}

1.4 开始新增映射

http://172.17.0.225:8888/v1/indices/add

或者

http://127.0.0.1:8888/v1/indices/add


参数

自定义分词器ik_pinyin_analyzer(ik和pinyin组合分词器)


tips 在创建映射前,需要安装拼音插件

{
 "indexName": "product_completion_index",
 "map": {
   "settings": {
     "number_of_shards": 1,
     "number_of_replicas": 2,
     "analysis": {
       "analyzer": {
         "ik_pinyin_analyzer": {
           "type": "custom",
           "tokenizer": "ik_smart",
           "filter": "pinyin_filter"
         }
       },
       "filter": {
         "pinyin_filter": {
           "type": "pinyin",
           "keep_first_letter": true,
           "keep_separate_first_letter": false,
           "keep_full_pinyin": true,
           "keep_original": true,
           "limit_first_letter_length": 16,
           "lowercase": true,
           "remove_duplicated_term": true
         }
       }
     }
   },
   "mapping": {
     "properties": {
       "name": {
         "type": "keyword"
       },
       "searchkey": {
         "type": "completion",
         "analyzer": "ik_pinyin_analyzer"
       }
     }
   }
 }
}

settings下面的为索引的设置信息,动态设置参数,遵循DSL写法

mapping下为映射的字段信息,动态设置参数,遵循DSL写法

返回

{
 "code": "200",
 "desc": "操作成功!",
 "data": true
}

2 语料库文档OpenAPI

2.1 定义批量新增文档接口

package com.oldlu.service;
import com.oldlu.commons.pojo.CommonEntity;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import java.util.List;
import java.util.Map;
/**
* @Class: ElasticsearchDocumentService
* @Package com.oldlu.service
* @Description: 文档操作接口
* @Company: 
*/
public interface ElasticsearchDocumentService {
  //批量新增文档
  public RestStatus bulkAddDoc(CommonEntity commonEntity) throws Exception;
}

2.2 定义批量新增文档实现

/*
  * @Description: 批量新增文档,可自动创建索引、自动创建映射
  * @Method: bulkAddDoc
  * @Param: [indexName, map]
  * @Update:
  * @since: 1.0.0
  * @Return: org.elasticsearch.rest.RestStatus
  *
  */
 @Override
 public RestStatus bulkAddDoc(CommonEntity commonEntity) throws Exception {
   //通过索引构建批量请求对象
   BulkRequest bulkRequest = new BulkRequest(commonEntity.getIndexName());
   //循环前台list文档数据
   for (int i = 0; i < commonEntity.getList().size(); i++) {
     bulkRequest.add(new IndexRequest().source(XContentType.JSON,
SearchTools.mapToObjectGroup(commonEntity.getList().get(i))));
   }
   //执行批量新增
   BulkResponse bulkResponse = client.bulk(bulkRequest,
RequestOptions.DEFAULT);
   return bulkResponse.status();
 }

官方文档介绍https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.4/java-rest-high-document-bulk.html


5a7429bc405e4042b7e94fd1250aff93.png

如上图,需要定义成箭头中的形式

所以上面SearchTools.mapToObjectGroup将map转成了数组


2.3 定义批量新增文档控制器

/*
  * @Description: 批量新增文档,可自动创建索引、自动创建映射
  * @Method: bulkAddDoc
  * @Param: [indexName, map]
  * @Update:
  * @since: 1.0.0
  * @Return: org.elasticsearch.rest.RestStatus
  *
  */
  @PostMapping(value = "/batch")
  public ResponseData bulkAddDoc(@RequestBody CommonEntity commonEntity) {
    //构造返回数据
    ResponseData rData = new ResponseData();
    if (StringUtils.isEmpty(commonEntity.getIndexName()) ||
CollectionUtils.isEmpty(commonEntity.getList())) {
      rData.setResultEnum(ResultEnum.PARAM_ISNULL);
      return rData;
 }
    //批量新增操作返回结果
    RestStatus result = null;
    try {
      //通过高阶API调用批量新增操作方法
      result = elasticsearchDocumentService.bulkAddDoc(commonEntity);
      //通过类型推断自动装箱(多个参数取交集)
      rData.setResultEnum(result, ResultEnum.SUCCESS, null);
      //日志记录
      logger.info(TipsEnum.BATCH_CREATE_DOC_SUCCESS.getMessage());
   } catch (Exception e) {
      //日志记录
      logger.info(TipsEnum.BATCH_CREATE_DOC_FAIL.getMessage(), e);
      //构建错误返回信息
      rData.setResultEnum(ResultEnum.ERROR);
   }
    return rData;
 }

2.4 开始批量新增调用

http://172.17.0.225:8888/v1/docs/batch

或者

http://127.0.0.1:8888/v1/docs/batch

参数

定义23个suggest词库(定义了两个小米手机,验证是否去重)

{
 "indexName": "product_completion_index",
 "list": [
   {
     "searchkey": "小米手机",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米10",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米电视",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米路由器",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米9",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米手机",
"name": "小米(MI)"
   },
   {
     "searchkey": "小米耳环",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米8",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米10Pro",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米笔记本",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米摄像头",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米电饭煲",
     "name": "小米(MI)"
   },
   {
     "searchkey": "小米充电宝",
     "name": "小米(MI)"
   },
   {
     "searchkey": "adidas男鞋",
     "name": "adidas男鞋"
   },
   {
     "searchkey": "adidas女鞋",
     "name": "adidas女鞋"
   },
   {
     "searchkey": "adidas外套",
     "name": "adidas外套"
   },
   {
     "searchkey": "adidas裤子",
     "name": "adidas裤子"
   },
   {
     "searchkey": "adidas官方旗舰店",
     "name": "adidas官方旗舰店"
   },
   {
     "searchkey": "阿迪达斯袜子",
     "name": "阿迪达斯袜子"
   },
    {
     "searchkey": "阿迪达斯外套",
     "name": "阿迪达斯外套"
   },
   {
     "searchkey": "阿迪达斯运动鞋",
     "name": "阿迪达斯运动鞋"
   },
   {
     "searchkey": "耐克外套",
     "name": "耐克外套"
   },
   {
     "searchkey": "耐克运动鞋",
     "name": "耐克运动鞋"
   }
 ]
}

返回

{
 "code": "200",
 "desc": "操作成功!",
 "data": "OK"
}

查看GET product_completion_index/_search

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
1月前
|
Java Maven 开发工具
【ElasticSearch 】IK 分词器安装
【ElasticSearch 】IK 分词器安装
44 1
|
12天前
|
自然语言处理 数据可视化 Linux
ElasticSearch安装ik分词器_使用_自定义词典
ElasticSearch安装ik分词器_使用_自定义词典
16 1
|
1月前
|
存储 数据建模 索引
来自钉钉群的问题——Elasticsearch 如何实现文件名自定义排序?
来自钉钉群的问题——Elasticsearch 如何实现文件名自定义排序?
27 0
|
1月前
|
Linux Docker 容器
使用Docker来安装ElasticSearch,并且配置ik分词器
使用Docker来安装ElasticSearch,并且配置ik分词器
68 0
|
1月前
|
存储 自然语言处理 算法
elasticsearch集群搭建,以及kibana和ik分词器的安装(7.3.2)
elasticsearch集群搭建,以及kibana和ik分词器的安装(7.3.2)
|
1月前
|
自然语言处理 搜索推荐 应用服务中间件
Elasticsearch 外部词库文件更新
Elasticsearch 外部词库文件更新
51 1
|
1月前
|
自然语言处理
Elasticsearch+IK+pinyin自定义分词器
Elasticsearch+IK+pinyin自定义分词器
39 0
|
1月前
|
自然语言处理 数据可视化 算法
史上最详细Docker安装Elasticsearch、ik分词器、可视化工具,每一步都带有步骤图!!!
史上最详细Docker安装Elasticsearch、ik分词器、可视化工具,每一步都带有步骤图!!!
566 0
史上最详细Docker安装Elasticsearch、ik分词器、可视化工具,每一步都带有步骤图!!!
|
1月前
|
Java Windows
windows下 安装 Elasticsearch报错warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME
windows下 安装 Elasticsearch报错warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME
152 0
|
12天前
Elasticsearch安装配置文件
Elasticsearch安装配置文件
15 0