Elasticsearch 之(21)前缀搜索、通配符搜索、正则搜索、推荐搜索 和 模糊搜索

一、前缀搜索
搜索包含KDKE前缀的articleID
GET /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"
        }
      }
    ]
  }
}
二、前缀搜索的原理
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"java

"articleID": "QQPX-R-3956-#aD8""articleID": "XHDK-A-1293-#fJ3"

KDKE --> 先扫描到了 KDKE-B-9947-#kL5,很棒,找到了一个前缀带 KDKE的字符串 --> 仍是要继续搜索的,由于也许还有其余不少的前缀带 KDKE的字符串 --> 你扫描到了一个前缀匹配的term,不能停,必须继续搜索 --> 直到扫描完整个的倒排索引,才能结束

由于实际场景中,可能有些场景是全文检索解决不了的

KDKE-B-9947-#kL5

KD --> match --> 扫描整个倒排索引,能找到吗

KD --> 只能用prefix

prefix性能不好


三、通配符搜索
跟前缀搜索相似,功能更增强大

5字符-D任意个字符5

5?-*5:通配符去表达更加复杂的模糊搜索的语义

GET /forum/article/_search
{
  "query": {
    "wildcard": {
      "articleID": {
        "value": "*Q?PX*8"
      }
    }
  }
}

?:任意字符
*:0个或任意多个字符

性能同样差,必须扫描整个倒排索引,才ok

四、正则搜索

GET forum/article/_search
{
  "query": {
    "regexp": {
      "articleID": "K[A-Z].+"
    }
  }
}
K[A-Z].+

[0-9]:指定范围内的数字
[a-z]:指定范围内的字母
.:一个字符
+:前面的正则表达式能够出现一次或屡次

wildcard和regexp,与prefix原理一致,都会扫描整个索引,性能不好

主要是给你们介绍一些高级的搜索语法。在实际应用中,能不用尽可能别用。性能太差了。

五、搜索推荐
搜索推荐,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,就再也不继续搜索倒排索引了。

尽可能不要用,由于,最后一个前缀始终要去扫描大量的索引,性能可能会不好

六、误拼写时的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"
      }
    }
  }
}