通过IK分词器与自定义词库实现精准关键词搜索
通过配置自定义主词词库和停词词库,并结合IK分词器的ik_max_word和ik_smart组合策略,使专有词语在索引与检索阶段均能被完整识别,最终实现关键词搜索精准命中率显著提升。
应用场景
在电商、医疗、企业知识库等场景中,默认分词器和IK预置词库往往无法精准识别行业专有名词(如品牌名被拆散、医学术语被误切),导致搜索召回率低、精准度差。通过IK分词器结合自定义主词词库和停词词库,可让专有词语被完整保留、无意义干扰词被过滤,实现精准的关键词搜索。
典型应用:
- 电商商品搜索:避免品牌名、产品型号等专有名词被错误切分,防止搜索结果混乱。
- 医疗健康检索:确保医学术语、药品名称、疾病名称被完整识别,提升检索准确性。
- 法律文书检索:防止法律专用词语、机构名称被拆散,保障文书精准定位。
- 企业内部知识库:解决内部项目名、技术术语、人名等被默认分词器错误切分的问题。
- 内容社区运营:避免因网络流行词、热点词汇未被收录而影响内容召回效果。
方案架构
- 索引阶段:原始数据经过IK分词器分词。主词词库确保专有词语被完整保留,停词词库过滤无意义词语,分词结果写入倒排索引进行存储。
- 查询阶段:搜索关键词经过IK分词器分词。分词结果与倒排索引进行匹配,召回相关文档。
- 词库加载层:自定义词库(主词词库和停词词库)通过OBS动态加载,无需重启集群即可生效;预置词库(静态主词词库、静态停词词库、Extra主词词库和Extra停词词库)由CSS内置维护,提供常用词语的基础覆盖。
- 组合策略:写入用细粒度分析器ik_max_word,穷举所有词组组合写入索引,确保搜索时不遗漏,提升召回率;查询用粗粒度分析器ik_smart,只取最合理的分词结果进行匹配,避免噪音干扰,提升准确性。
方案优势
- 零中断动态更新:自定义词库通过OBS动态加载,更新词库后无需重启集群,业务完全无感知。
- 双粒度组合策略:写入(ik_max_word)+ 查询(ik_smart)的组合模式,在召回率与精准度之间取得最佳平衡。
- 按需裁剪:停词词库可将无意义的高频词(如“的”、“是”、“了”)从索引中剔除,降低索引存储体积,提升查询性能。
- 灵活扩展:词库文件独立维护于OBS,支持随业务发展持续追加新词,运营人员即可操作,无需开发介入。
约束限制
- 集群版本要求:2018年3月10日之前创建的集群,不支持自定义词库功能。本文的示例代码基于OpenSearch集群和Elasticsearch 7.x版本的集群,Elasticsearch集群版本低于7.x的操作命令请参见示例代码(Elasticsearch版本<7.x)。
- IK分词器主要用于中文分词,如果用于英文,仅#、&、+、-、.、@、_视为普通字符保留,其余特殊字符均作为切分点将文本切分为独立词组。
前提条件
- 目标集群处于“可用”状态,无正在进行中的任务。
- 确认操作账号已具备以下权限(可以在IAM服务的“权限管理 > 权限”中查看和配置):
- 配置自定义词库的权限:
"css:IKThesaurus:*"
- OBS桶及对象的读取权限:
obs:bucket:getBucketLocation obs:bucket:getBucketStoragePolicy obs:bucket:listAllMyBuckets obs:object:getObject
- 如果OBS桶使用SSE-KMS加密模式时,还需KMS权限:
"kms:cmk:create", "kms:dek:create", "kms:cmk:get", "kms:dek:decrypt", "kms:cmk:list"
- 配置自定义词库的权限:
步骤一:准备词库文件
准备主词词库和停词词库,并上传至OBS桶中。
步骤二:配置自定义词库
为集群配置自定义的主词词库和停词词库,使IK分词器能识别业务专有词语并过滤干扰词。
- 登录云搜索服务管理控制台。
- 在左侧导航栏,根据集群类型选择“集群管理 > Elasticsearch”或“集群管理 > OpenSearch”。
- 在集群列表,单击目标集群名称,进入集群详情页。
- 选择“集群配置 > 自定义词库”,进入自定义词库配置页面。
- 根据业务需求配置自定义词库。
表1 配置自定义词库 参数名称
操作说明
OBS桶
选择词库文件所在的OBS桶。
主词词库
选择“更新 > 选择”,选择OBS桶中已上传的主词词库文件“main_custom.txt”,单击“确定”。
停词词库
选择“更新 > 选择”,选择OBS桶中已上传的停词词库文件“stop_custom.txt”,单击“确定”。
同义词词库
保持默认值“不更新”,表示不配置该词库。
- 配置完成后,单击“保存”,在弹窗中单击“确定”,启动词库更新。
下方呈现词库配置信息。等待约1分钟,词库状态从“更新中”变更为“成功”,表示词库更新完成。
图2 词库状态
步骤三:验证分词效果
- 在自定义词库页面,单击页面右上角的“Kibana”或“Dashboards”。
- 在Kibana或Dashboards左侧导航栏选择“Dev Tools”,进入操作页面。
- 执行以下命令,查看ik_smart的分词效果。
GET /_analyze { "analyzer": "ik_smart", "text": "容灾备份以及冗余架构可以保障系统高可用运行" }预期结果:
{ "tokens" : [ { "token" : "容灾备份", "start_offset" : 0, "end_offset" : 4, "type" : "CN_WORD", "position" : 0 }, { "token" : "冗余", "start_offset" : 6, "end_offset" : 8, "type" : "CN_WORD", "position" : 1 }, { "token" : "架构", "start_offset" : 8, "end_offset" : 10, "type" : "CN_WORD", "position" : 2 }, { "token" : "保障系统", "start_offset" : 12, "end_offset" : 16, "type" : "CN_WORD", "position" : 3 }, { "token" : "高可用", "start_offset" : 16, "end_offset" : 19, "type" : "CN_WORD", "position" : 4 }, { "token" : "运行", "start_offset" : 19, "end_offset" : 21, "type" : "CN_WORD", "position" : 5 } ] }结果解读:“容灾备份”和“高可用”被识别为独立词,“以及”和“可以”作为停词被过滤,说明词库配置生效。
步骤四:创建索引
创建索引并指定写入和查询时使用的IK分词器,实现双粒度组合策略。
执行以下命令,创建索引book,写入时使用ik_max_word分析器,查询时使用ik_smart分析器。
PUT /book
{
"settings": {
"number_of_shards": 2,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
} 预期结果:
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "book"
} 步骤五:写入测试数据
写入测试数据,用于验证关键词检索效果。
执行以下命令,将测试文本写入索引book。
POST /book/_bulk
{"index":{"_id":"1"}}
{"content":"容灾备份以及冗余架构可以保障系统高可用运行"}
{"index":{"_id":"2"}}
{"content":"容灾方案成本高"}
{"index":{"_id":"3"}}
{"content":"企业从架构层面推进数据备份的落地改造"} 预期结果:
{
"took" : 5,
"errors" : false,
"items" : [
{ "index" : { "_index" : "book", "_type" : "_doc", "_id" : "1", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 0, "_primary_term" : 1, "status" : 201 } },
{ "index" : { "_index" : "book", "_type" : "_doc", "_id" : "2", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 1, "status" : 201 } },
{ "index" : { "_index" : "book", "_type" : "_doc", "_id" : "3", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 2, "_primary_term" : 1, "status" : 201 } }
]
} 步骤六:执行关键词搜索
通过关键词搜索验证自定义词库的配置效果。
- 执行以下命令,搜索主词“容灾备份”:
GET /book/_search { "query": { "match": { "content": "容灾备份" } } }预期结果:
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 2, "successful" : 2, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 0.89470756, "hits" : [ { "_index" : "book", "_type" : "_doc", "_id" : "1", "_score" : 0.89470756, "_source" : { "content" : "容灾备份以及冗余架构可以保障系统高可用运行" } } ] } }结果解读:因为主词词库中包含“容灾备份”,仅文档1被召回。
- 文档1在写入时ik_max_word将“容灾备份”作为完整词条保留在倒排索引中,搜索时ik_smart也将其识别为独立词,精准匹配。
- 文档2原文为“容灾方案”,ik_max_word切分出“容灾”但不含完整的“容灾备份”;文档3原文为“数据备份”,切分出“备份”但不含“容灾备份”,因此均无法召回。
- 执行以下命令,搜索停词“可以”:
GET /book/_search { "query": { "match": { "content": "可以" } } }预期结果:
{ "took" : 0, "timed_out" : false, "_shards" : { "total" : 2, "successful" : 2, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 0, "relation" : "eq" }, "max_score" : null, "hits" : [ ] } }结果解读:停词“可以”在数据写入时被IK分词器过滤,未进入倒排索引,因此搜索时无结果返回,说明停词词库生效。
示例代码(Elasticsearch版本<7.x)
当Elasticsearch集群版本低于7.x时,需要自定义type名称,参考以下命令。
- 执行以下命令,创建索引book并指定IK分词器。
PUT /book { "settings": { "number_of_shards": 2, "number_of_replicas": 1 }, "mappings": { "type1": { "properties": { "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" } } } } } - 执行以下命令,将测试数据写入索引book。
POST /_bulk { "index" : { "_index" : "book", "_type" : "type1", "_id" : "1" } } { "content" : "容灾备份以及冗余架构可以保障系统高可用运行" } { "index" : { "_index" : "book", "_type" : "type1", "_id" : "2" } } { "content" : "容灾方案成本高" } { "index" : { "_index" : "book", "_type" : "type1", "_id" : "3" } } { "content" : "企业从架构层面推进数据备份的落地改造" } - 执行以下命令,通过关键词搜索验证配置结果。
GET /book/type1/_search { "query": { "match": { "content": "容灾备份" } } }