es实现mysql的like
方案一、可以是用wildcard通配符,但是要设置不分词,这种方案性能不好 方案二、可以使用ngram分词器 “min_gram”: 2,”max_gram”: 3 单词假设是 abcde0001 ab bc cd abc cde 001.。。。等等 被分词2个字母一组和3个字符一组。。、。
注意空格 如a bcde0001 https://www.cnblogs.com/rainersha/p/11982846.html
前缀匹配
代码语言:javascript复制假设es中有条这样的数据,前缀匹配(不分词)
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的性能是很高的。。
通配符
代码语言:javascript复制通配符 是不分词的所以要设置成keyword
GET my_index/my_type/_search
{
"query": {
"wildcard": {
"title": {
"value": "C?K*5"
}
}
}
}
?:任意字符
*:0个或任意多个字符
性能一样差,必须扫描整个倒排索引,才ok
正则
代码语言:javascript复制一样不分词
GET /my_index/my_type/_search
{
"query": {
"regexp": {
"title": "C[0-9]. "
}
}
}
C[0-9].
[0-9]:指定范围内的数字
[a-z]:指定范围内的字母
.:一个字符
:前面的正则表达式可以出现一次或多次
wildcard和regexp,与prefix原理一致,都会扫描整个索引,性能很差
近似/短语匹配
代码语言:javascript复制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
代码语言:javascript复制假设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
代码语言:javascript复制什么是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位,符合我们的期望的
completion
代码语言:javascript复制es实现completion,不会构建倒排索引页不会构建正排索引,就是纯的用于进行前缀
搜索的一种特殊的数据结构,而且会全部放在内存中,所以auto completion进行的
前缀搜索提示,性能是非常高的
PUT /news_website
{
"mappings": {
"news" : {
"properties" : {
"title" : {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"suggest" : {
"type" : "completion",
"analyzer": "ik_max_word"
}
}
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
PUT /news_website/news/1
{
"title": "大话西游电影",
"content": "大话西游的电影时隔20年即将在2017年4月重映"
}
PUT /news_website/news/2
{
"title": "大话西游小说",
"content": "某知名网络小说作家已经完成了大话西游同名小说的出版"
}
PUT /news_website/news/3
{
"title": "大话西游手游",
"content": "网易游戏近日出品了大话西游经典IP的手游,正在火爆内测中"
}
GET /news_website/news/_search
{
"suggest": {
"my-suggest" : {
"prefix" : "大话西游",
"completion" : {
"field" : "title.suggest"
}
}
}
}
注意这里讲“大话西游”设置成一个热词,会被当成一个分词组。
模糊搜索
代码语言:javascript复制GET /my_index/my_type/_search
{
"query": {
"fuzzy": {
"text": {
"value": "surprize",
"fuzziness": 2
}
}
}
}
surprize --> surprise -> z -> s,纠正一个字母,就可以匹配上,所以在fuziness指定的2范围内
surprize --> surprised -> z -> s,末尾加个d,纠正了2次,也可以匹配上,在fuziness指定的2范围内
surprize --> surprising -> z -> s,去掉e,ing,3次,总共要5次,才可以匹配上,始终纠正不了
fuzziness:不写默认是2