Es实战理解记录

ES实战理解
指定es索引内存储数据结构
POST forum/doc/1
{
"title": "hello world", #文章标题
"message": "i am a simple message", #文章内容
"id": "62", #文章id
"uid": "1038", #唯一id
"comments": "1",
"views": "1231",
"addtime": "1456042765",
"votes": "12",
"category_id": "2"
}

优化查询
前缀查询(Prefix 查询)
GET forum-mysql/_search
{
"query": {
"prefix": {
"title": {
"value": "elas"
}
}
},"_source": "title"
}
查询前几条结果分别为:
● Day 20 - Elastic性能实战指南
● Day 13 - Elasticsearch-Hadoop打通Elasticsearch和Hadoop
● …
● Elastic日报 第473期 (2018-12-09)
使用效果与不足之处
可以看到,Prefix 查询生效了,能够通过部分字母查到完整的数据,但是前面几条数据貌似有点奇怪,比如第一条,开头的数据不是 Elas,而是 Day 20,为什么会这样呢?明明使用的是 prefix 查询啊?

原因:答案就在我们所使用的字段是 title 字段,title 字段是 text 的类型,也就是会应用文本分析器将原始的字符串拆分成了若干个词语,而我们这里的 prefix 查询是对词语级别进行的前缀匹配,而如果一个字段拆分之后,就变成了若干个词语,所以在查询的时候,其实每个词语都是平等的,都会进行一个前缀匹配,任意词语匹配上查询都算这个字段匹配上这个查询,而不会管这些词语原始的字符串的顺序。
所以,我们不能使用分词的字段来使用 prefix 查询,我们可以使用 title.keyword 这个字段,这个字段是不分词的。修改之后的查询如下:
prefix-titlekeyword(不分词查询)
GET forum-mysql/_search
{
"query": {
"prefix": {
"title.keyword": {
"value": "elas"
}
}
},"_source": "title"
}
优化后结果:
● elasticsearch优秀实践
● elasticsearch-官网中文文档
● …
使用效果与不足之处
但是使用不分词查询后,如果执行普通的文本查询怎么办,比如搜索 Elasticsearch SQL,结果却搜索不出来了,这个不妙,总不能捡了芝麻丢了西瓜啊,有没有办法同时支持这两种查询呢?
BOOl查询就可以很好的同时支持两种查询方式,在 Elasticsearch 内部有多种类型的查询,其中有一些查询类型是用来组合其他查询的,示例如下:
Bool(组合查询)
GET forum-mysql/_search
{
"query": {
"bool": {
"should": [
{
"prefix": {
"title.keyword": {
"value": "Elasticsearch SQL"
}
}
},
{
"match": {
"title": {
"query": "Elasticsearch SQL"
}
}
}
]
}
},
"_source": "title"
}
使用后效果与不足之处
为了保证查询的效果,我们对上面的查询关键字换另外查询试试看,换成的 spark 的结果共有5条,分别是:
● elastic-spark classNotFount EsSpark
● spark elasticsearch 异常: PowerSet: Too many elements to create a power set 40
● 使用 ES-Hadoop 将 Spark Streaming 流数据写入 ES
● 如何使用Spark快速将数据写入Elasticsearch
● spark1.6.3+elasticsearch5.4 netty jar冲突
但是发现我们想要的效果:
优先保证不分词匹配为先,分词后匹配结果为后(并不理想)
spar 作为前缀匹配命中了2条结果,准确率效果不错,但是太严格了,还有一些和 spark 相关的,但是不是开头的文章没有找出来,假如文档都不是 spark 开头,那就会出现找不到,我们可以优先 spark 开头的在前面,不过也应该容忍出现在其他的位置,尤其是 spark 作为开头的位置没有的情况下。
我们的 bool 查询其实在 should 里面组合了两个子条件,这两个子条件是平等的关系,任意满足即可将命中返回,但是其实我们是希望这些查询有一些偏好倾向的,对应这样的两种问题,我们可以通过设置boost 权重来控制这些子条件命中结果的命中得分来调整最后返回结果的顺序。修改过后的查询如下:
boost-权重控制
GET forum-mysql/_search
{
"query": {
"bool": {
"must": [],
"should": [
{
"prefix": {
"title.keyword": {
"value": "spark",
"boost": 10
}
}
},
{
"match": {
"title": "spark"
}
}
]
}
},
"_source": "title"
}
优化后的查询结果:
● spark elasticsearch 异常: PowerSet: Too many elements to create a power set 40
● spark1.6.3+elasticsearch5.4 netty jar冲突
● elastic-spark classNotFount EsSpark
● 使用 ES-Hadoop 将 Spark Streaming 流数据写入 ES
● Day 8 - 如何使用Spark快速将数据写入Elasticsearch
根据目前的匹配效果继续测试查询:
下面使用 elastic 上海作为key查询,得到的查询结果如下:
● 上海Elasticsearch技术沙龙
● 上海普翔招聘 Elastic技术支持工程师
● [线下活动] 2017-05-14 Elastic Meetup 上海日程
● ESCC#4上海站视频录像照片PPT
● 7月21日,周六,Elastic 上海 线下 Meetup [活动结束, PPT已上传]
使用后效果与不足之处
匹配结果发现只有第五条是最符合想要的查询,但是却排在了比较靠后的位置
原来,我们的条件是一个句子,Elasticsearch 同样会在搜索的时候,对查询的关键字进行文本分析处理,将一个长句子拆分成多个词语,分别对这些词语进行倒排索引的搜索。例如用来测试分析结果的例子:
请求

GET forum-mysql/_analyze
{
"field": "title",
"text": ["elastic 上海"]
}
返回匹配结果:
{
"tokens" : [
{
"token" : "elastic",
"start_offset" : 0,
"end_offset" : 7,
"type" : "",
"position" : 0
},
{
"token" : "上",
"start_offset" : 8,
"end_offset" : 9,
"type" : "",
"position" : 1
},
{
"token" : "海",
"start_offset" : 9,
"end_offset" : 10,
"type" : "",
"position" : 2
}
]
}
原因:
索引的这个 title 字段使用的是默认的 standard analyzer,会进行简单的文本拆分,对于中文则是一个字一个字的拆分的,在测试的查询中,第一个通过关键字的 prefix 前缀匹配应该是没有任何命中数据的,而第二个match 查询则分别通过这四个关键字:elastic、上、海 在索引里面进行倒排索引的匹配。
这些关键字在处理的时候,是并列关系,但是其实在输入关键字的时候,其实是希望这句条件是有先后顺序的,也就是我们希望的应该是 elastic 上海 优先于 上海 elastic 的
match_phrase 查询
match_phrase 查询,相比 match 查询多了一个词语位置关系的处理,添加一个 match_phrase 查询,并权重比 match 查询要高,同时比 prefer 查询低。
GET forum-mysql/_search
{
"size": 5,
"query": {
"bool": {
"must": [],
"should": [
{
"prefix": {
"title.keyword": {
"value": "elastic 上海",
"boost": 10
}
}
},
{
"match_phrase_prefix": {
"title": {
"query": "elastic 上海",
"boost": 2
}
}
},
{
"match": {
"title": "elastic 上海"
}
}
]
}
},
"_source": "title"
}
执行查询效果:
● 7月21日,周六,Elastic 上海 线下 Meetup [活动结束, PPT已上传]
● 上海Elasticsearch技术沙龙
● 上海普翔招聘 Elastic技术支持工程师
● [线下活动] 2017-05-14 Elastic Meetup 上海日程
● ESCC#4上海站视频录像照片PPT
模糊查询
在用户提供检索词的时候,经常会有出现拼写错误的情况
例如:将elastic拼写为:elastik、elasic、eastic等等结果就是会拿不到任何匹配结果
而在es索引里面我们有一个 Term 词典方便我们来快速检测某个 Term 在不在索引里面。
字符相似(概念)
虽然我们 Term 词典里面没有 elastik,但是却有 elastic 啊,所以,这里就要看如何计算这俩字符的相似度了,这里有一个编辑距离的概念(Lucene 里面使用的是莱文斯坦距离,Levenshtein edit distance),指的是给定两个不同的字符串,把一个字符串转换成另外一个所需的最少的编辑操作次数。如果查询的 Term 和索引的 Term 在编辑 N 个词之后能够匹配得上,那么我们认为这样也算是满足(容忍)匹配的需求。而这个编辑距离也就是控制我们模糊匹配的范围。elastic 将末尾 c 编辑为 k 即可匹配上 elastik,该 Term 所对应的文档即可返回,这里的编辑距离 N 也就是 1。
可以看看这里的几个字符串之间通过编辑转换的例子:
● elastix => elastic, 编辑距离1,替换x 为 c
● elasti => elastic,编辑距离1,末尾插入字符c
● elasticd => elastic,编辑距离1,删除字符d
所以,通过简单的插入、修改和删除,可以将一个字符转换为另外一个字符,他们还是比较相似的嘛。
查询的 FUZZINESS 参数
在 Elasticsearch 里面,对字符类型的字段使用全文查询时,如 Match Query,可以通过设置 fuzziness 参数来控制查询的模糊匹配的程度。fuzziness 参数可以设置为:
● 0, 1, 2, 可以设置为具体的编辑距离,最大为2。
● AUTO,自动模式,基于词语的长度来自动选择编辑距离,还支持可选的格式 AUTO:[low],[high] 来设置一个字符的距离规则范围,如果不指定参数 low 和 high,默认是3和6,也就是 AUTO:3,6, 对于不同的字符串,则会有这样的编辑距离规则:
● 0..2,对于长度小于2的字串,必须绝对匹配
● 3..5,对于长度范围3到5的字串,允许一个编辑距离
● >5,对于长度大于5的字串,允许两个编辑距离
AUTO 模式能够自动根据字符串的长度进行选择,所以优先使用 AUTO 模式。
举例如下:
DELETE test

POST test/doc/1
{
"doc":"elastic"
}

POST test/doc/2
{
"doc":"elastik"
}

GET test/_search
{
"query": {
"match": {
"doc":{
"query": "elastix",
"fuzziness": "AUTO"
}
}
}
}
注意啦,不是所有的查询都支持 fuzziness 参数的。除了 Match Query,还有 QueryString Query 和 Simple Query String Query 也支持。他们的参数也各不相同,所以在使用的时候,还请查询官方的 API 手册。
fuzzy_transpositions-字符间的位置变换
另外,fuzzy 还支持是否运行将字符的位置变换作为一次编辑,在 Match Query 里面默认是启用的,如下:elastic -> elsatic,假如我们不希望位置变换,我们可以设置参数 fuzzy_transpositions 为 false,如下:
GET test/_search
{
"query": {
"match": {
"doc":{
"query": " elsatic",
"fuzziness": "1",
"fuzzy_transpositions":false
}
}
}
}
prefix_length-限制内容开头第n个字符必须完全匹配
表示限制输入关键字和ES对应查询field的内容开头的第n个字符必须完全匹配,不允许错别字匹配
max_expansions-限制模糊查询匹配量
因为,fuzzy 查询会将查询尝试变换成其他的条件,所以会把一个条件 expand 成很多条件,我们可以通过参数来 max_expansions 来进行限制,默认值是 50。
FUZZY QUERY-es提供的独立查询
Elasticsearch 还提供了一个独立的 Fuzzy Query,不过参数有一些变化,使用 transpositions 来控制是否开启位置变换,且默认是禁止的,同样支持 fuzziness、prefix_length 和 max_expansions。例如:
GET test/_search
{
"query": {
"fuzzy": {
"doc":{
"value": " elsatic",
"fuzziness": "AUTO",
"transpositions":true
}
}
}
}
注意此处的例子里面,条件 elsatic的第一个字符是空格,如果再加一个空格就会查不到数据,为什么呢?
因为,相比在 Match 里面使用 fuzziness 参数来支持模糊查询,Fuzzy Query 参数里面传递的 value 条件将作为一个 Term 整体,也就是不会进行任何的文本分析处理,空格的移除也会变成一次编辑,在这里的 AUTO 模式会允许两次编辑,但是我们需要移除两次空格和一次位置变换,也就是3,所以自然也就查询不到索引里面的 elastic 了。
WILDCARD-通配符查询
例如在使用 Access 或是其它系统的时候,有一种处理模糊条件的办法,就是用 ? 代替不知道的单个字符,用 * 代表任意多个字符。我们一般叫这种查询为通配符查询。 如 elasti? 可以匹配上 elastic 以及 elas* 同样可以匹配上 elastic。
使用示例:
GET test/_search
{
"query": {
"wildcard": {
"doc": {
"value": "elasti?"
}
}
}
}
上面的查询会同时匹配上索引里面的 elstic 和 elstik。
注意:Wildcard 在使用的时候一定要特别小心,因为它的性能比较差,尤其是不要让用户在输入的条件里面,第一个字符就以通配符(如:lasi)来开头,因为 wildcard 要遍历所有可能的 Term 词典,范围越大,代价越大。
作为一个搜索框,如果也能够支持支持通配符搜索给用户,当然是大大的方便了用户啊。加上加上。
REGEX-正则匹配查询
Elasticsearch 支持的正则表达式不是和 Perl 语法的正则表达式兼容的,只是一部分子集,另外,正则表达式查询和通配符查询都是对分词之后的倒排索引的 Term 进行的匹配,不是原始的字符串,这一点一定要弄清楚了。如 elas.
可以匹配上 elastic。
使用示例:
GET test/_search
{
"query": {
"regexp": {
"doc":{
"value": "elas.*"
}
}
}
}
注意:正则表达式虽然威力强大,但是用的不好也会造成很大的性能问题。条件越具体越精确越好,避免歧义,尽量确保正则表达式左端前缀匹配的足够长,且不要以通配符开头。
QUERY STRING 查询(包含了很多模糊查询的方式、模糊、通配符、正则等等)
Elasticsearch 的 Query String Query ,它支持对查询条件进行解析,从而自动进行查询的改写,通配符查询、正则表达式查询都支持,选择字段,设置权重,甚至还有范围查询、多字段查询、短语查询等等,对于我们现在想拥有的效果非常适合使用。
使用实例(正则):
GET test/_search
{
"query": {
"query_string": {
"query": "/elasti[ck]+/"
}
}
}
注意,如果是正则表达式,请使用 / 作为开头和结尾。
allow_leading_wildcard-禁止在查询条件开头输入通配符
查询一切正常,我们还通过设置 allow_leading_wildcard 为 false 来禁止用户在查询条件开头输入通配符,保证查询性能。
这样,我们就不用担心用户输入正则表达式和通配符没有结果的问题了,我们可以在用户输入框的地方,给一下提示说明或者帮助文字,这些算是额外支持的高级用法。

posted @   比啾比啾  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示