学习目标
前缀匹配
通配符匹配
正则匹配
近似/短语匹配
搜索推荐
原文地址 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