ES拼音前缀索引

大家观察淘宝的首页搜索框,它除了支持中文前缀搜索提示外,还支持拼音前缀搜索提示。

拼音分为全拼和首字母两种,ES拼音分词插件需要用开源项目:elasticsearch-analysis-pinyin

当我们要索引”2018世界杯”的时候,我们期望产生2种分词结果:

2018shijiebei和2018sjb,即全拼和首拼,我们不需要类似于2018 shi jie bei这种的单字分词。

然后,我们利用ES的edge-ngram filter,将上述2种分词结果,做前缀切分。

2018shijiebei被filter拆成多个term建立倒排:

  • 2
  • 20
  • 201
  • 2018
  • 2018s
  • 2018sh
  • 2018shi
  • 2018shij
  • 2018shiji
  • 2018shijie

类似的,2018sjb被拆成:

  • 2
  • 20
  • 201
  • 2018
  • 2018s
  • 2018sj
  • 2018sjb

一旦”2018世界杯”被映射成了这么多term的倒排,那么我们输入任意的前缀搜索词,均可以完成召回。

我现在将全拼和首拼都用一个analyzer拆分,但是建议大家还是把全拼和首拼分成2个anaylzer,这样搜索时相关性打分会更科学,下面看一下配置。

tokenizer

首先配置tokenizer,它的工作是把”2018世界杯”切分成全拼和首拼,一共就2个term。

如果我们要索引”世界杯worldcup”,那么keep_none_chinese=true则会导致把非中文部分拆出1个独立的term:worldcup,这不是我们希望的,我们只需要shijiebeiworldcup或者sjbworldcup,所以这个选项需要设置false。

其他的配置非常容易理解,看注释即可。

filter

接着,需要利用ES内置的edge-ngram filter,把全拼和首字拼按前缀拆term,也就是上面我们列举的大量的前缀term:

analyzer

最后,我们利用tokenizer+filter来生成一个自定义的分析器:

大家注意,analyzer的工作顺序是char_filter -> tokenizer -> filter,我们没有用到char_filter字符过滤。

搜索

搜索时一般应该利用termQuery,不需要对搜索词做分词,但是应该考虑做一些基本处理,比如转换小写,去除标点符号。

因此,我们可以配置一个用于search搜索词处理的analyzer,令其tokenizer使用keyword(不分词),通过char_filter阶段实现标点符号的过滤,通过filter阶段实现大小写转换。

有了search_analyzer,我们可以走matchQuery来应用它,确保搜索词和倒排能容易吻合。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~