ES中文分词器之精确短语匹配(解决了match_phrase匹配不全的问题)

分词器选择

调研了几种分词器,例如IK分词器,ansj分词器,mmseg分词器,发现IK的分词效果最好。举个例子:

词:<<是的>><span>哈<\span>撒多撒ئۇيغۇر تىلى王者荣耀sdsd@4342啊啊啊

Standard: 是,的,span,哈,span,撒,多,撒,ئۇيغۇر,تىلى,王,者,荣,耀,sdsd,4342,啊,啊,啊,啊

mmseg_maxword:是,的,span,哈,span,撒,多,撒,ئ,ۇ,ي,غ,ۇ,ر,ت,ى,ل,ى,王者,荣耀,sdsd,4342,啊,啊,啊,啊

IK_max_word:是的,span,哈,span,撒,多,撒,王者,王,者,荣耀,荣,耀,sdsd,4342,sdsd@4342,啊啊啊,啊啊,啊,啊啊,啊

Ansj: <,<,是,的,>,>,<,span,>,哈,<,\,span,>,撒,多,撒,ئ,ۇ,ي,غ,ۇ,ر,ت,ى,ل,ى,王者,荣耀,sdsd,@,4342,啊,啊,啊,啊

在上述例子中,IK和Mmsg 用的同一套词典。Ansj和IK,Mmsg使用的不是一套词典,也没有配置停词。

本文讲的中文分词器就是IK分词器。

分词器需要达到的效果

1)短语可以精确匹配
2)查找时间要比standard少
3)如果查找的词语不在词典中,也必须要查到
4)如果数据在原文中出现,就一定要查全

IK分词器短语精确匹配的问题

楼主意淫着将所有的单字放入词典中,这样用ik_max_word 对数据建索引时既可以把词分出来建索引,又可以把字分出来建索引。然后用 ik_smart 将查找短语,因为ik_smart分出的数据是 ik_max_word 的一个子集,如果要查找的短语在原文中有出现,那么一定可以查到。后来发现用ik_smart分词器查找句子(match_phrase)时一个都没有查到,exo???为什么会查不到呢?明明是一个子集。对此官方网站对match_phrase的解释如下:

Like the match query, the match_phrase query first analyzes the query string to produce a list of terms. It then searches for all the terms, but keeps only documents that contain all of the search terms, in the same positions relative to each other.

意思就是说用match_phrase查找时,查找分词器分出的词的位置和要建索引时分出的词的位置一样。举个例子:

原文:快乐感恩
ik_max_word:快乐 1 快 2 乐感 3 乐 4 感恩 5 感 6 恩 7
ik_smart:快乐 1 感恩 2

从上面可以看出,查找时ik_smart将语句分为了快乐和感恩两个词,位置分别为1和2,而ik_max_word建索引时,快乐和感恩的位置分别是1和4,在match_phrase看来,这种是不匹配的,所以用ik_smart分词短语时无法查到或者查全数据。

好吧,既然ik_smart无法查到,我用ik_max_word查找总行了吧。用上述的例子,查找”快乐“时,你会发现你用ik_max_word查找到的结果没有standard分词器建索引查找获取到的结果多。原因和上述讲的一样:

查找词语:快乐
ik_max_word:快乐 1 快 2 乐 3

在构建索引的时候,快乐,快和乐的位置分别是1,2,4,而查找时分词的顺序是1,2,3,然后match_phrase认为其不匹配,因此查询不到这种结果。

网上答案

遇到问题了,在网上寻求解决方案。看了几篇博客,都指出了match_phrase的这个匹配问题,解决方案有以下两种:

1) standard分词器
2) NGram分词器

standard分词器大家都比较熟,针对于汉字就是一个一个分,这种肯定是可以查全的。但一个一个字分的话,每个字对应的文档集合非常多,如果数据量达到了百亿,在求交集,计算距离时,效果非常差。

Ngram分词器类似于standard分词器,他可以指定分词的长度,然后用standard的方法切割。比如说“节日快乐”,我们指定切割的长度为2,NGram会切成“节日”,“日快”,“快乐”。虽然查找时可以减少每个token对应的文档数,但是存储量会增大很多,而且不在支持模糊的match匹配。很土。

求解过程

ik_max_word构建索引,ik_smart无法查找,原因是ik_max_word分出了所有的词,ik_smart只分出了一种词,由于match_phrase本身的限制导致ik_smart查找不到。那我构建的时候采用ik_smart,查找的时候也用ik_smart,这样只要原文中有数据,构建和查找用同一种分词方法,就应该可以查找得到。测试后发现,这种也有很大的问题,即像“潜行者”这样的词,只分为了“潜行”和“者”两个token,但是“行者”也是一个词,在查找“行者”时无法查全数据。

ik_smart无法查全的原因是只分出了一种词的可能性,导致有些词查询不全。ik_max_word能解决这个问题。。但是ik_max_word的问题是如果查找的最后一个字能和原文中这个字的下一个字组成词语,那么就会出现无法查全的问题。我们能不能让ik_max_word将词和字分开?

当然可以,对一个属性指定两种分词方法:

curl -XPUT 'xxx/my_test_both?pretty' -H 'Content-Type: application/json' -d'
{"mappings": {
        "my_type": {
            "properties": {
                "ulluin": { 
                    "type": "text",
                    "fields": {
                            "ik":{"type":"text","analyzer": "ik_max_word"}
                        }
                    }
                }
         }
    }
}'

这样ulluin属性采用standard分词,即单字分词,ulluin.ik采用ik_max_word即按词分词,ik_max_word的词典中去除所有的单字

查询时先将查询短语分词,如果第一个token和最后一个token中存在一个字,那么这个字可能与原文中的下一个字或者上一个字组成词,导致ik_max_word无法查到,这时我们用standard分词器在ulluin中查询,如果第一个token和最后一个token都是词,那么说明可以在ik_max_word中查询。来吧,测试一下:

原文:节日快乐龙哥
ik_max_word:节日 1 快乐龙 2 快乐 3 龙哥 4
查询短语:节日快乐
ik_max_word:节日 1 快乐 2

为什么还是有问题?????ik_max_word查出的数据量比standard的少???还是因为match_phrase的限制,索引中“节日”和“快乐”的位置是1和3,而查找时“节日”和“快乐”的位置是1和2。这个问题很好解决,用match_phrase_prefix查询即可,即:

curl -XGET 'xxx/my_test_both/_search?pretty' -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_phrase_prefix" : {
                "ulluin" : {
                    "query" : "节日快乐"
                }
         }
    },
    "size":1
}' 

上面还提到ik_max_word有一个问题是分出的词语比standard的多,我们过滤了单字分词后,这个效果就会有很大的提升。假设我们的词典没有四字分词,只有二三字。比如说

原词:中华人民共和国
修改前:中华,中,华人,华,人民,人,民,共和国,共和,和,国
修改后:中华,华人,人民,共和国,共和

可以看出,修改后的效果要比standard的效果好的多,不但token数变少了,而且每个token对应的文档数也大大的降低,减少了求交集的数据量和计算距离的数据量。

至此总算解决了ES中文分词切精确匹配的问题。

源码修改:

* 修改IK不支持小语种的问题 
* 修改中文之间特殊字符不能过滤的问题。即原文“节 日 快 乐”不能匹配“节日快乐”的问题。
* 修改量词,数词单独分出的问题。修改前“一天天”分为“一天天,一天,一,天天,天”,修改后分为“一天天,一天,天天”。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容