橡皮、老虎皮、狮子皮哪一个最不好?

ES6.3.2 match查询时如何"过滤"只包含特定字符串的document?

Elasticsearch | 作者 hapjin | 发布于2019年08月29日 | 阅读数:428

用户输入一个查询字符串,比如"ABCD",同时指定一个过滤规则:"EF",如何返回"ABCD"查询结果中,只包含"EF"的文档?[这里的 "只包含" 的意思就是: JDK中java.lang.String#contains]
示例如下:
我有一个名为user_v1的索引,nick字段的mapping定义如下:nick是text类型,nick.raw是keyword类型。
"nick": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
},
"analyzer": "hanlp_standard"
}


 
match查询字符串:"微天加看有"
GET user_v1/profile/_search
{
"_source": "nick",
"query": {
"match": {
"nick": "微天加看有"
}
}
}
返回的部分结果如下:
{
"_index": "user_v1",
"_type": "profile",
"_id": "204",
"_score": 17.63079,
"_source": {
"nick": "看有糖"
}
},
{
"_index": "user_v1",
"_type": "profile",
"_id": "578",
"_score": 17.63079,
"_source": {
"nick": "看有月亮"
}
},
{
"_index": "user_v1",
"_type": "profile",
"_id": "737",
"_score": 17.63079,
"_source": {
"nick": "看有太阳"
}
},
{
"_index": "user_v1",
"_type": "profile",
"_id": "19",
"_score": 17.63079,
"_source": {
"nick": "看有怪兽"
}
},
{
"_index": "user_v1",
"_type": "profile",
"_id": "16",
"_score": 17.63079,
"_source": {
"nick": "看[u][b]有飞[/b][/u]机"
}
}
指定过滤规则:"有飞",我只想让ES返回:在查询 "微天加看有" 时,包含字符串"有飞" 的文档。也即:在所有的返回文档中,nick这个字段必须满足,nick.contains("有飞")==true 条件的文档才能返回。
这个如何实现?
 
我现在的实现思路是:当 match query "微天加看有" 时,采用scroll 翻页,把每一页的结果取到本地内存,然后字符串匹配检查nick中是否包含 "有飞"(nick.contains("有飞")==true),但是这样当命中量一大,效率就太低了。有什么好的实现方案吗?或者说通过ES的插件机制来实现,也就是说让ES来做匹配检查,而不是把文档取回到内存里面做匹配检查
 
补充一下需求:
用户输入查询字符串"ABCD"搜索nick字段,ES match query 返回nick字段的搜索结果。用户根据返回的搜索结果,随机标一串字符(比如标出来是"EF"),如何返回:在搜索"ABCD"的结果中,快速地找出只包含 "EF" 的文档?
 
其实就是想实现 MySQL 中 like %xxx% 查询完全等价的功能(要考虑analyzer)。不知道大家有没有什么好的方案?
 
 
 
 
已邀请:

hapjin

赞同来自:

本来以为ES的 source-filtering 能够匹配过滤 _source 中的内容,但 source filter 只是确定是否 返回 某个字段,与我的问题一点也不相干。

hapjin

赞同来自:

另外想过修改Analyzer来满足上述需求,不管是用中文分词还是用Standard Analyzer或其他分词器,貌似都不能满足上述要求。因为,用户指定的过滤规则是随机的一段字符串,并不符合分词。也有可能是我没有彻底理解Analyzer。

hapjin

赞同来自:

看了下  match_pharse 查询再加上 slop 这个参数的作用,可以"部分"地实现上述功能。只是match_pharse 查询会对查询字符串进行analyze 。如果用户随机标的 一串字符 分词之后得到的term,如果 与文档索引入ES时Analyze 的term不一样时,match_pharse 就不能命中这样的文档了,会影响召回率。
 
如果设置文档索引到ES时的analyzer 为:那种能够 text tokenize 成 一个个 char 的分析器的话,又需要自己写一个Analyzer插件,并且处理各种特殊符号、标点符号的问题,而且还涉及中英文字符如何分割的问题:
"hello  world  你好"--->['h','e','l','l','o','w','o','r','l','d','你','好']才能符合要求。。。
 

hapjin

赞同来自:

看了下 n-gram tokenizer (min_gram、 max_gram 都设置成 1) ,再配合 match_pharse 查询(slop设置成0),应该是能解决 这种 随机 选择一段字符串作为搜索条件的吧?没人讨论一下么?

要回复问题请先登录注册