用ES实现拼音搜索策略
构建拼音索引
Step 1 在ES中安装pinyin分词器
安装步骤详见网上的众多介绍,这里不赘述,「链接」。pinyin的开源见:GitHub - medcl/elasticsearch-analysis-pinyin: This Pinyin Analysis plugin is used to do conversion between Chinese characters and Pinyin.
Step 2 新建索引并初始化测试数据PUT idx_test_user { "mappings": { "dynamic": false, "properties": { "name": { "analyzer": "standard", "type": "text", "fields": { "pinyin": { "type": "text", "analyzer": "index_pinyin_analyzer" } } } } }, "settings": { "analysis": { "analyzer": { "index_pinyin_analyzer": { // MARK 1 "tokenizer": "index_pinyin_tokenizer" }, "search_pinyin_analyzer": { // MARK 2 "tokenizer": "search_pinyin_tokenzier" } }, "tokenizer": { "index_pinyin_tokenizer": { "keep_joined_full_pinyin" : "true", "lowercase" : "true", "none_chinese_pinyin_tokenize" : "false", "keep_none_chinese_in_joined_full_pinyin" : "true", "keep_original" : "true", "keep_none_chinese_together" : "true", "remove_duplicated_term" : "false", "keep_separate_first_letter" : "false", "type" : "pinyin", "limit_first_letter_length" : "16", "keep_full_pinyin" : "true" }, "search_pinyin_tokenzier": { "keep_joined_full_pinyin" : "true", "lowercase" : "true", "keep_original" : "true", "remove_duplicated_term" : "false", "keep_separate_first_letter" : "false", "type" : "pinyin", "limit_first_letter_length" : "16", "keep_full_pinyin" : "true" } } } } } POST idx_test_user/_doc/1 { "name": "李超" } POST idx_test_user/_doc/2 { "name": "李超越" } POST idx_test_user/_doc/3 { "name": "刘超" } POST idx_test_user/_doc/4 { "name": "李朝" }
代码示例 1.1
【MARK 1说明】analyzer根据使用的位置不同(索引侧、召回侧),有可能需要定义不同的analyzer,两侧的analyzer搭配在一起使用,共同构成一组搜索策略。MARK 1处为索引侧analyzer
【MARK 2说明】该analyzer用于召回侧,与MARK 1的analyzer组合在一起使用
索引侧analyzer效果说明
以代码示例1.1中的测试数据为例,在倒排索引中的结果是这样的
token
doc:李超
doc:李超越
doc:刘超
doc:李朝
li "start_offset" : 0,
"end_offset" : 0,
"position" : 0 "start_offset" : 0,
"end_offset" : 0,
"position" : 0
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
李超 "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
-
-
lichao "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
lc "start_offset" : 0,
"end_offset" : 0,
"position" : 0
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0 "start_offset" : 0,
"end_offset" : 0,
"position" : 0
chao "start_offset" : 0,
"end_offset" : 0,
"position" : 1 "start_offset" : 0,
"end_offset" : 0,
"position" : 1 "start_offset" : 0,
"end_offset" : 0,
"position" : 1 "start_offset" : 0,
"end_offset" : 0,
"position" : 1
李超越
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
-
lichaoyue
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
-
lcy
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
-
yue
- "start_offset" : 0,
"end_offset" : 0,
"position" : 2
-
-
liu
-
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
刘超
-
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
liuchao
-
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
-
李朝
-
-
- "start_offset" : 0,
"end_offset" : 0,
"position" : 0
表 1.1 「李超」、「李超越」、「刘超」在倒排索引中的结构
召回侧实现方式"match_phrase": { // MARK 1 "name.pinyin": { "analyzer": "search_pinyin_analyzer", // MARK 2 "query": "lichao" } }
代码示例 2.1
【MARK 1说明】注意要使用match_phrase,而不是match,不然会有badcase
【MARK 2说明】注意这里要指定召回侧的analyzer,analyzer声明详见「 代码示例 1.1」 ,若不指定则会用ES默认analyzer:standard
拼音搜索策略及其效果
使用代码示例1.1中提供的数据,倒排索引结构见表1.1,召回DSL见代码示例2.1
query
全拼
连字拼音
前缀拼音
多音字
lichao
李超,李朝
李超越
-
-
lichaoyue
李超越
-
-
-
li
-
李超,李超越,李朝
-
-
chao
-
李超,李超越,刘超,李朝
-
-
yue
-
李超越
-
-
liuchao
刘超
-
-
-
liu
-
刘超
-
-
lc
-
-
不支持
-
lizhao
-
-
-
不支持,无法召回李朝
表 2.1 各query在不同策略下可以召回的结果
欢迎访问我的博客:用ES实现拼音搜索策略 百木森森的技术分享