背景
需求是存储时候分词词组是固定的,有关键词这一数据用|竖线连接,对于搜索时候只能匹配这些分割后的关键词词组。这就需要用到内置分词器Patter Analyzer,匹配规则是单竖线。找了好多文章零零散散,还是自己写个简单例子吧。
一、给字段定义分词规则
在springboot的resources下面建es文件夹,同时创建mapping.json、settings.json文件,文件名可以根据自己实际命名。
settings.json,使用pattern的正则匹配,用竖线作为分词规则。vertical_line是自定义分词器名字,后面直接引用这个名字。
{
"analysis": {
"analyzer": {
"vertical_line": {
"type": "pattern",
"pattern": "\\|"
}
}
}
}
mapping.json,question_info是@Document type值,properties里面是对应字段,这里对字段keyWords设置analyzer为vertical_line,就是存储时候分词使用竖线,然后search_analyzer查询分词器使用ik的ik_max_word最大限度分词。
{
"question_info": {
"properties": {
"keyWords": {
"type": "text",
"analyzer": "vertical_line",
"search_analyzer": "ik_max_word"
}
}
}
}
model,@Setting引用settings.json文件,@Mapping引用mapping.json文件,@Document 定义index名称以及mapping名称
package com.xxxx.model;
import java.util.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
/**
* 描述:xxx实体类
* @author sakyoka
* @date 2024-09-25 17:22:56
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "question_info", type = "question_info")
//自定义分割,产品要求关键词查询,关键词由|竖线符号连接
@Setting(settingPath = "es/settings.json")
@Mapping(mappingPath = "es/mapping.json")
public class QuestionInfoModel {
/** 主键*/
@Id
private String id;
/** 关键词*/
private String keyWords;
}
二、初始化 index
好了,给实体类配置好之后还需要初始化index逻辑,这里我的想法是项目启动初始化一遍。
package com.xxxx.listener;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
/**
*
* 描述:启动完之后初始化配置
* @author sakyoka
* @date 2022年1月15日 下午9:36:12
*/
@Component
@Slf4j
public class SpringStartCompleteInitConfigListener implements CommandLineRunner{
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Override
public void run(String... args) throws Exception {
try {
log.info("检测es index,进行初始化...");
List<Class<?>> clss = new ArrayList<>(1);
clss.add(QuestionInfo.class);
clss.stream().filter(cls -> {
//已经存在的跳过
return !elasticsearchRestTemplate.indexExists(cls);
}).forEach(cls -> {
//创建index
elasticsearchRestTemplate.createIndex(cls);
//添加mapping
elasticsearchRestTemplate.putMapping(cls);
});
log.info("检测es index完毕。");
} catch (Exception e) {
log.error("初始化es index失败", e);
}
}
}
这里初始化值得注意的是 elasticsearchRestTemplate.createIndex(cls)仅仅是创建了index和setting数据。如果要给字段引用对应分词器规则还需要putMapping 、elasticsearchRestTemplate.putMapping(cls);
好了,启动项目之后,测试一下效果。
postman测试es请求,由于之前开启了登录,postman需要设置一下认证信息,在authorization选在Basic auth填写对应账号密码
1、首先查询下,建立index逻辑看是否正确,可以看到index里面包含了自定义分词规则,以及对应字段引用了自定义分词器。
2、测试分词规则,可以看到分词器按照竖线分词
3、真实数据测试,这里就不测试了。。
三、词库追加自定义词组(补)
经测试,存储分词达到自己用竖线分词,但是用ik的ik_max_word去分词,发现没有达到自己的效果,用ik_max_word去分词发现少了一些词组,最后发现是词库没有这词组。那现在就需要给ik的词库添加自己想要的词组。
进入到es目录,进入到plugins,找到ik(需要自己去上传解压到这个目录),进入config目录,添加自定义词库文件,这里简单定义创建my.dic,往里面塞词组,这里添加港澳通行证,因为经测试这个词组出不来(6.8.12版本)
然后修改IKAnalyzer.cfg.xml,在ext_dict添加自己的自定义文件,添加好后重启es
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">my.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
最后发现能对这个分词了
总结
1、有个巨坑不知道为啥用注解@Field指定自定义分词器失败,然后这里才需要用mapping设置字段分词器,有朋友知道吗
2、mapping内容写法,不同版本写法还不一样。