Elasticsearch搜索特性

 

 

 

学习目标
前缀匹配
通配符匹配
正则匹配
近似/短语匹配
搜索推荐

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

 

前缀匹配

假设es中有3条这样的数据,前缀匹配(不分词)
C3D0-KD345
C3K5-DFG65
C4I8-UI365

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "title": {
          "type": "keyword"
        }
      }
    }
  }
}
需求:我们要通过"C3"来查找
1.使用match是搜索不到的
2.使用"prefix"
GET my_index/my_type/_search
{
  "query": {
    "prefix": {
      "title": {
        "value": "C3"
      }
    }
  }
}

前缀匹配性能很差。
因为前缀匹配,要扫描所有的倒排索引,假设“C3D0-KD345”
这条数据,并不能停止,因为不知道后面还有没有"C3"打头的。

match不一样(分词)
C3-D0-KD345   doc1
C3-K5-DFG65   doc2
C4-I8-UI365   doc3

C3  doc1  doc2
D0
KD345
K5
.....

match扫描到了"C3"就可以停止了,所以match的性能是很高的。。

通配符

通配符 是不分词的所以要设置成keyword
GET my_index/my_type/_search
{
  "query": {
    "wildcard": {
      "title": {
        "value": "C?K*5"
      }
    }
  }
}

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

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

正则

一样不分词
GET /my_index/my_type/_search 
{
  "query": {
    "regexp": {
      "title": "C[0-9].+"
    }
  }
}

C[0-9].+

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

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

近似/短语匹配

java is my favourite programming language, and I also think spark is a very good big data system.
java spark are very related, because scala is spark's programming language and scala is also based on jvm like java.

假设es有上面两句话(会分词)
1.我们需要查询“java spark”这个短语,两个单词会连在一起
2.我们需要查询“java spark”,这个短语,不一定子要连在一起,但是靠近越近,分数越高

需求1
match
1.分词“java”和“spark”
2.使用“java”去扫描倒排索引找出对应得doc返回
3.使用“spark”去扫描倒排索引找出对应得doc返回
所以match只能返回含有“java”或“spark”或两者都有的doc

term
1.不分词 “java spark”去扫描倒排索引找到对应得doc返回
当然至于doc字段分词和不分词看有没有设置成keyword。


所以上面match和term都没办法实现我们的需求

这个个时候我们要使用match_phrase
GET /forum/article/_search
{
    "query": {
        "match_phrase": {
            "content": "java spark"
        }
    }
}
match_phrase:原理
1.将"java spark"分词成"java"和"spark"
2.使用"java"扫描倒排索引得到doc,
3.使用"spark"扫描倒排索引得到doc,
hello world, java spark        doc1
hi, spark java                doc2

hello         doc1(0)        
wolrd        doc1(1)
java        doc1(2) doc2(2)
spark        doc1(3) doc2(1)
得到
java        doc1(2) doc2(2)
spark        doc1(3) doc2(1)
4.比较位置spark的位置要比大1 所以只有doc1


需求2
GET /forum/article/_search
{
    "query": {
        "match_phrase": {
            "title": {
                "query": "java spark",
                "slop":  1
            }
        }
    }
}
“slop”的含义
query string,搜索文本,中的几个term,要经过几次移动才能与一个document匹配,这个移动的次数,就是slop
例子:
hello world, java is very good, spark is also very good.

“java spark”,match phrase,搜不到
java        is        very        good        spark        is

java        spark
java        -->        spark
java                -->            spark
java                            -->            spark

所以我们将“slop”设置成3就行,意思是移动3步

假设我们现在要搜索
spark java呢
java        is        very        good        spark        is

spark        java
spark/java(java向左移动,重叠1步)     
java          spark(交换位置2步)
java        -->        spark
java                -->            spark
java                            -->            spark
所以我们将“slop”设置成5就行

搜索推荐------match_phrase_prefix

假设es中有
hello world
hello we
hello win
hello wind
hello dog
hello cat
将我们使用"hello w"去搜索希望能查出hello world hello we hello win hello wind
我们可以使用“match_phrase_prefix”
GET /my_index/my_type/_search 
{
  "query": {
    "match_phrase_prefix": {
      "title": "hello w"
    }
  }
}

原理
原理跟match_phrase类似,只是最后一个词语用前缀匹配
1.将“hello w”分词成“hello”和“w”
2.“hello”使用match去搜索对应得doc
3.“w”使用前缀匹配去扫描倒排索引中所有的数据(性能很差)
4.计算slop,“w”要刚好比“hello”的位置大1,当然也可以自己设置“slop”

这个方式性能很差,可以使用ngram来实现搜索推荐

搜索推荐------ngram

什么是ngram

quick,5种长度下的ngram

ngram length=1,q u i c k
ngram length=2,qu ui ic ck
ngram length=3,qui uic ick
ngram length=4,quic uick
ngram length=5,quick

什么是edge ngram

quick,anchor首字母后进行ngram

q
qu
qui
quic
quick

使用edge ngram将每个单词都进行进一步的分词切分,用切分后的ngram来实现前缀搜索推荐功能

helloworld
min ngram = 1
max ngram = 3
h
he
hel
搜索的时候,不用再根据一个前缀,然后扫描整个倒排索引了; 简单的拿前缀去倒排索引中匹配即可,如果匹配上了,那么就好了; match,全文检索
1.给index创建一个分词器 
PUT /my_index
{
    "settings": {
        "analysis": {
            "filter": {
                "autocomplete_filter": { 
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter" 
                    ]
                }
            }
        }
    }
}
测试分词器的效果
GET /my_index/_analyze
{
  "analyzer": "autocomplete",
  "text": "quick brown"
}
2.给index创建mapping
PUT /my_index/_mapping/my_type
{
  "properties": {
      "title": {
          "type":     "string",
          "analyzer": "autocomplete",
          "search_analyzer": "standard"
      }
  }
}

3.

GET /my_index/my_type/_search 
{
  "query": {
    "match_phrase": {
      "title": "hello w"
    }
  }
}
如果用match,只有hello的也会出来,全文检索,只是分数比较低
推荐使用match_phrase,要求每个词语都有,而且position刚好靠着1位,符合我们的期望的

 

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

原文地址 http://www.54288.top/article/view.do?articleId=138

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值