Elasticsearch 之(21)前缀搜索、通配符搜索、正则搜索、推荐搜索 和 模糊搜索
1、前缀搜索
搜索包含KDKE前缀的articleIDGET /forum/article/_search { "query": { "prefix": { "articleID": { "value": "KDKE" } } } } { "took": 52, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": "forum", "_type": "article", "_id": "2", "_score": 1, "_source": { "articleID": "KDKE-B-9947-#kL5", "userID": 1, "hidden": false, "postDate": "2017-01-02", "tag": [ "java" ], "tag_cnt": 1, "view_cnt": 50, "title": "this is java blog", "content": "i think java is the best programming language", "sub_title": "learned a lot of course", "author_first_name": "Smith", "author_last_name": "Williams" } } ] } }
2、前缀搜索的原理
prefix query不计算relevance score,与prefix filter唯一的区别就是,filter会cache bitset
扫描整个倒排索引,举例说明
前缀越短,要处理的doc越多,性能越差,尽可能用长前缀搜索
前缀搜索,它是怎么执行的?性能为什么差呢?
match"articleID": "KDKE-B-9947-#kL5""articleID": "QQPX-R-3956-#aD8""articleID": "XHDK-A-1293-#fJ3"
全文检索
每个字符串都需要被分词
KDKE doc1,doc2
KDKE
B
9947
#kL5
QQPX
....
KDKE --> 扫描倒排索引 --> 一旦扫描到KDKE,就可以停了,因为带KDKE的就1个doc,已经找到了 --> 没有必要继续去搜索其他的term了
match性能往往是很高的
不分词
"articleID": "KDKE-B-9947-#kL5"
"articleID": "QQPX-R-3956-#aD8""articleID": "XHDK-A-1293-#fJ3"
KDKE --> 先扫描到了KDKE-B-9947-#kL5,很棒,找到了一个前缀带KDKE的字符串 --> 还是要继续搜索的,因为也许还有其他很多的前缀带KDKE的字符串 --> 你扫描到了一个前缀匹配的term,不能停,必须继续搜索 --> 直到扫描完整个的倒排索引,才能结束
因为实际场景中,可能有些场景是全文检索解决不了的
KD --> match --> 扫描整个倒排索引,能找到吗
KD --> 只能用prefix
prefix性能很差
3、通配符搜索
跟前缀搜索类似,功能更加强大
5字符-D任意个字符5
5?-*5:通配符去表达更加复杂的模糊搜索的语义
GET /forum/article/_search { "query": { "wildcard": { "articleID": { "value": "*Q?PX*8" } } } }
?:任意字符
*:0个或任意多个字符
性能一样差,必须扫描整个倒排索引,才ok
4、正则搜索
GET forum/article/_search { "query": { "regexp": { "articleID": "K[A-Z].+" } } }
K[A-Z].+
[0-9]:指定范围内的数字
[a-z]:指定范围内的字母
.:一个字符
+:前面的正则表达式可以出现一次或多次
wildcard和regexp,与prefix原理一致,都会扫描整个索引,性能很差
主要是给大家介绍一些高级的搜索语法。在实际应用中,能不用尽量别用。性能太差了。
5、搜索推荐
搜索推荐,search as you type,搜索提示hello w --> 搜索 hello world hello we hello win hello wind hello dog hello cat hello w --> hello world hello we hello win hello wind搜索推荐的功能
百度 --> elas --> elasticsearch --> elasticsearch权威指南
GET forum/article/_search { "query": { "match_phrase_prefix": { "content": { "query": "i elas", "slop":5, "max_expansions": 1 } } } }原理跟match_phrase类似,唯一的区别,就是把最后一个term作为前缀去搜索
i就是去进行match,搜索对应的doc
elas,会作为前缀,去扫描整个倒排索引,找到所有elas开头的doc
然后找到所有doc中,即包含i,又包含elas开头的字符的doc
根据你的slop去计算,看在slop范围内,能不能让hello w,正好跟doc中的hello和w开头的单词的position相匹配
也可以指定slop,但是只有最后一个term会作为前缀
max_expansions:指定prefix最多匹配多少个term,超过这个数量就不继续匹配了,限定性能
默认情况下,前缀要扫描所有的倒排索引中的term,去查找w打头的单词,但是这样性能太差。可以用max_expansions限定,w前缀最多匹配多少个term,就不再继续搜索倒排索引了。
尽量不要用,因为,最后一个前缀始终要去扫描大量的索引,性能可能会很差
6、误拼写时的fuzzy模糊搜索
搜索的时候,可能输入的搜索文本会出现误拼写的情况doc1: hello world
doc2: hello java
搜索:hallo world
fuzzy搜索技术 --> 自动将拼写错误的搜索文本,进行纠正,纠正以后去尝试匹配索引中的数据
POST /my_index/my_type/_bulk { "index": { "_id": 1 }} { "text": "Surprise me!"} { "index": { "_id": 2 }} { "text": "That was surprising."} { "index": { "_id": 3 }} { "text": "I wasn't surprised."}
GET /my_index/my_type/_search { "query": { "fuzzy": { "text": { "value": "surprize", "fuzziness": 2 } } } }surprize --> 拼写错误 --> surprise --> s -> z
surprize --> surprise -> z -> s,纠正一个字母,就可以匹配上,所以在fuziness指定的2范围内
surprize --> surprised -> z -> s,末尾加个d,纠正了2次,也可以匹配上,在fuziness指定的2范围内
surprize --> surprising -> z -> s,去掉e,ing,3次,总共要5次,才可以匹配上,始终纠正不了
fuzzy搜索以后,会自动尝试将你的搜索文本进行纠错,然后去跟文本进行匹配
fuzziness,你的搜索文本最多可以纠正几个字母去跟你的数据进行匹配,默认如果不设置,就是2
GET /my_index/my_type/_search { "query": { "match": { "text": { "query": "SURPIZE ME", "fuzziness": "AUTO", "operator": "and" } } } }