JDK8+elasticsearch-7.17.21+分词器(elasticsearch-analysis-ik-7.17.21)实现相似度查询
·
摘要:
本文介绍了在JDK8环境下使用Elasticsearch7.17.21结合ik分词器实现文本相似度查询的方法。主要内容包括:1)环境准备,要求JDK1.8.x、ES7.17.21和匹配版本的ik分词器;2)创建索引并指定ik分词器;3)三种相似度查询方式(match、multi_match和fuzzy查询)的实现;4)Java代码示例,展示如何使用RestHighLevelClient构建查询并解析结果。文章还提供了优化建议,如选择合适的分词器、调整评分权重和处理拼写错误等,以提升查询效果。
实现步骤(完整可落地)
前置准备
- 环境确认:
- JDK 版本:1.8.x(ES 7.17.x 要求 JDK8 或 11,优先 8)
- ES 版本:7.17.21
- IK 分词器:elasticsearch-analysis-ik-7.17.21(需与 ES 版本严格一致)
- IK 分词器安装:
bash
运行
# 进入 ES 插件目录 cd elasticsearch-7.17.21/plugins # 创建 ik 目录 mkdir ik cd ik # 下载对应版本的 ik 分词器压缩包并解压(或手动下载后上传) wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.21/elasticsearch-analysis-ik-7.17.21.zip unzip elasticsearch-analysis-ik-7.17.21.zip # 重启 ES 生效 cd ../../bin ./elasticsearch -d
步骤 1:创建索引(指定 IK 分词器)
首先创建索引,并为字段指定 IK 分词器(ik_max_word 细粒度分词 /ik_smart 粗粒度分词),这是相似度查询的基础。
请求示例(REST API):
http
PUT /article_index
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": {
"analyzer": {
"ik_analyzer": { # 自定义 ik 分词器
"type": "custom",
"tokenizer": "ik_max_word", # 细粒度分词(适合相似度查询)
"filter": ["lowercase"] # 转小写,避免大小写影响匹配
}
}
}
},
"mappings": {
"properties": {
"title": { # 要做相似度查询的字段
"type": "text",
"analyzer": "ik_analyzer", # 使用自定义 ik 分词器
"search_analyzer": "ik_analyzer"
},
"content": {
"type": "text",
"analyzer": "ik_analyzer",
"search_analyzer": "ik_analyzer"
}
}
}
}
步骤 2:插入测试数据
http
POST /article_index/_bulk
{"index":{"_id":1}}
{"title":"Java 高并发编程实战","content":"讲解 Java 并发编程的核心原理和实战案例"}
{"index":{"_id":2}}
{"title":"Java 并发编程艺术","content":"深入剖析 Java 并发编程的底层实现"}
{"index":{"_id":3}}
{"title":"Python 高并发编程","content":"Python 异步编程和多线程实战"}
步骤 3:实现相似度查询(核心)
ES 实现相似度查询的核心是基于分词的相关性评分,常用 3 种方式,按实用性排序:
方式 1:match 查询(最常用,基于 TF-IDF 评分)
match 查询会先对查询词做 IK 分词,再匹配文档,返回按相似度评分(_score)排序的结果。
http
GET /article_index/_search
{
"query": {
"match": {
"title": {
"query": "Java 并发编程", # 查询词
"minimum_should_match": "70%" # 至少匹配 70% 的分词项(提升精准度)
}
}
}
}
返回结果(核心部分):
json
{
"hits": [
{
"_id": "1",
"_score": 1.8234, # 相似度评分(越高越相似)
"_source": {"title":"Java 高并发编程实战"}
},
{
"_id": "2",
"_score": 1.5678,
"_source": {"title":"Java 并发编程艺术"}
},
{
"_id": "3",
"_score": 0.2345,
"_source": {"title":"Python 高并发编程"}
}
]
}
方式 2:multi_match 查询(多字段相似度匹配)
同时对多个字段(如 title + content)做相似度查询,适合全文检索场景。
http
GET /article_index/_search
{
"query": {
"multi_match": {
"query": "Java 并发编程",
"fields": ["title^2", "content"], # title 权重×2(更关注标题)
"type": "best_fields", # 取匹配度最高的字段评分
"minimum_should_match": "60%"
}
}
}
方式 3:fuzzy 查询(模糊匹配,容错输入错误)
适合处理查询词有拼写错误的场景(如把「并发」写成「并法」),基于编辑距离(Levenshtein)实现。
http
GET /article_index/_search
{
"query": {
"fuzzy": {
"title": {
"value": "Java 并法编程", # 含拼写错误的查询词
"fuzziness": "AUTO", # 自动适配编辑距离(单字错误可匹配)
"prefix_length": 1 # 前缀 1 个字符不模糊(提升精准度)
}
}
}
}
步骤 4:Java 代码实现(JDK8 适配)
以下是基于 ES 官方 Java High Level REST Client(7.17.21)的代码示例,实现相似度查询:
1. 引入依赖(Maven)
xml
<dependencies>
<!-- ES High Level Client -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.17.21</version>
</dependency>
<!-- ES 核心依赖 -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.17.21</version>
</dependency>
<!-- JDK8 兼容依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.5</version>
</dependency>
</dependencies>
2. 核心代码
java
运行
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import java.io.IOException;
public class ESSimilarityQuery {
// 创建 ES 客户端(7.17.21 适配 JDK8)
private static RestHighLevelClient createClient() {
return new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "http"))
);
}
// 相似度查询(match 方式)
public static void searchSimilar(String indexName, String field, String queryText) throws IOException {
RestHighLevelClient client = createClient();
// 1. 构建查询条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery(field, queryText)
.minimumShouldMatch("70%")); // 至少匹配 70% 分词项
sourceBuilder.from(0);
sourceBuilder.size(10); // 返回前 10 条
// 2. 构建搜索请求
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(sourceBuilder);
// 3. 执行查询
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
// 4. 解析结果
System.out.println("相似度查询结果:");
for (SearchHit hit : response.getHits().getHits()) {
String id = hit.getId();
float score = hit.getScore(); // 相似度评分
String source = hit.getSourceAsString();
System.out.printf("ID: %s, 相似度评分: %.4f, 内容: %s%n", id, score, source);
}
// 关闭客户端
client.close();
}
public static void main(String[] args) {
try {
// 查询 "title" 字段中与 "Java 并发编程" 相似的文档
searchSimilar("article_index", "title", "Java 并发编程");
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码说明:
RestHighLevelClient:ES 7.x 官方推荐的客户端,适配 JDK8;matchQuery:核心相似度查询语法,结合 IK 分词器的结果做 TF-IDF 评分;minimumShouldMatch:控制匹配的严格程度,值越高越精准(如 80% 只返回高度相似的文档);getScore():获取文档的相似度评分(0~∞),评分越高表示越相似。
关键优化点(提升相似度查询效果)
- 分词器选择:
- 相似度查询优先用
ik_max_word(细粒度分词),能拆分更多关键词,提升匹配维度; - 若需精准匹配,可混用
ik_smart+ 关键词权重。
- 相似度查询优先用
- 评分优化:
- 通过
boost调整字段权重(如title^2让标题权重是内容的 2 倍); - 结合
function_score自定义评分规则(如按发布时间、点击量加权)。
- 通过
- 容错处理:
- 对长文本查询,使用
match_phrase(短语匹配)+slop(允许短语偏移),提升语义相似度; - 对拼写错误,叠加
fuzzy查询。
- 对长文本查询,使用
验证查询效果
- 运行 Java 代码后,控制台会输出文档 ID、相似度评分和内容;
- 评分越高的文档,与查询词「Java 并发编程」的相似度越高;
- 可通过调整
minimum_should_match的值,测试不同严格程度的匹配结果。
总结
- 实现核心:先为字段配置 IK 分词器,再通过
match/multi_match/fuzzy查询实现相似度检索,ES 会基于 TF-IDF 自动计算相似度评分; - Java 适配:使用 ES 7.17.21 版本的 High Level Client,完全兼容 JDK8,核心是构建
matchQuery并解析评分结果; - 效果优化:优先用
ik_max_word分词,通过minimum_should_match和字段权重(boost)调整匹配精准度。
更多推荐




所有评论(0)