【ES系列】DSL查询进阶


引言

基于上一章节对DSL的基础认识,这一篇将进阶了解其他不同的查询方法,并且对于常用搜索场景作详细解释。


查询方式分类

上一章节的几种查询属于基本查询跟组合查询。

模糊搜索

上一章提到Elasticsearch 的wildcard(通配符查询)、regexp(正则查询)、prefix(前缀查询),他们都是致力于模糊搜索,然后在实际的项目中该如何选择,稍不注意就可能到很大性能问题。由于它们是常用的搜索语法,但实际搜索类型却不同,这里做个概述,详细分别查看各标题。

绝大多数情况下,搜索内容都是针对文本类型(text和keyword)

当搜索字段是text类型时:由于它会分词,在执行wildcard、regexp、prefix时和es会检查字段中的每个词条,而不是整个字段。

当搜索字段是keyword类型时:在执行wildcard、regexp、prefix时和es会检查字段中整个文本

prefix查询

如果满足你的需求,前缀匹配是优于wildcard和regexp。

regexp查询和wildcard查询

避免使用一个以通配符开头的模式(比如,*foo或者正则表达式: .*foo),运行这类查询是非常消耗资源的。

最后再提醒下,如果你想了解它的执行过程及耗时情况(优化项从这里分析),查询是添加profile语法。

基本查询

基本查询内部包可以包含其他查询,只有索引检索这一个用途。这类查询通常作为其他辅助出现呢的一部分或者单独传递给Elasticsearch。可以把基本查询比作修筑大厦的砖块(根据英文文档翻译),而大厦就是各种复杂查询。举个例子吗如果陪陪谋份文档中的一个特定词项,并且不关心文档中词项的顺序,也没有其他的需求,就可以考虑使用基本查询。

match查询

一般来说,当需要分析输入内容却不需要完整的Lucene查询语法解析,发生解析错误的概率极低,因此特别适合处理用户输入文本的场景。

# 这是对于搜索条件没有其他约束的写法
{
	# 这里将返回执行这条语句的耗时的分布情况
	"profile" : true,
    "query":{
        "match":{
            "此处为字段名称":"此处填写需要查询的名称"
        }
    }
}

match_all查询

这个查询匹配所有文档,常用于需要对所有索引内容进行归类处理的场景(考虑到搜索效率,一般不建议使用,match搜索就足够了。)

索引和搜索时都会进⾏分词,查询字符串先传递到⼀个合适的分词器,然后⽣成⼀个供查询的词项列表 查询时候,先会对输⼊的查询进⾏分词,然后每个词项逐个进⾏底层的查询,最终将结果进⾏合并。并为每个⽂档⽣成⼀个算分。- 例如查 “elastic products”,会查到包括 elastic 或者 products的所有结果

# 这是对于搜索有其他字段约束时的语法
{
  "query": {
    "match": {
      "目标字段":{
        "query": "elastic products",
        "minimum_should_match": 2, # 限制最小包含数
        "operator": "AND" #这就会同时包含两个词项
      }
    }
  }
}

prefix 查询是一个词级别的底层的查询,它不会在搜索之前分析查询字符串,它假定传入前缀就正是要查找的前缀。

wildcard查询

这是实际业务中运用比较多的场景,通配符查询可以实现某个字段中包含一些字符的情况,并会返回所有满足条件的结果。当然,如果分词的索引列表过长,性能就不那么乐观了。

# 这会返回目标字段中包含es的所有情况
{
    "query": {
        "wildcard": {
            "目标字段": "*es*"
        }
    }
}

查询重写

ES对用户查询进行了重写,这样做为了保证性能。重写过程是吧lucene角度认为原始的、开销大的查询对象转变成一系列开销小的查询对象的一个过程。对于每一个查询,ES几乎都会涉及到重写分数。
但有些时候(比如文章标题或者某个文件名称),我们并不关心它搜索结果的排名,我们只想知道这个词是否在文档中出现过,那么重写算分的过程就似乎没有意义。那么这个时候的查询可以通过constant_score约束,比如还是match搜索elastic products。

{
  "query": {
    "bool": {
      "should": [
        { "constant_score": {
          "query": { "match": { "目标字段": "elastic" }}
        }},
        { "constant_score": {
          "query": { "match": { "目标字段": "products" }}
        }}
      ]
    }
  }
}

小结

以上几种方式在实际业务中被广泛使用,尤其是match搜索。wildcard能满足数据中的所有情况,但需要注意性能的因素,所以需要谨慎使用。
如果在搜索的过程中,并不关心目标结果的打分跟重写机制,可以使用constant_score来约束。


组合查询

组合查询的优势在于,能够处理各种复杂的查询情况,可以过滤并设置与或非的情况。但也并非可以无限嵌套下去,Elasticsearch对bool查询中最多使用1024个词项。当然这个限制,也可以在ES的yaml文件中修改indices.query.bool.max_clause_count属性设置这个值。需要注意的是,bool查询的条件嵌套的越多,查询的性能就越低。

bool查询

最常见的组合查询方式之一。能够把多个查询逻辑用布尔组织在一起,可以控制查询的某个子查询部分是必须匹配、可以匹配还是不应该匹配。

多区间或多字段查询
# 这里表示多时间区间的或查询,每个range当中举例了ES支持的不同时间区间的写法
# bool should的搜索为或的关系;must为与的关系。
{
    "query":{
        "bool":{
            "should":[
                {
                    "range":{
                        "目标时间字段":{
                        	# 这里是指过去一年到现在的时间区间
                            "gte": "now-1y/y", # 大于等于
                            "lte": "now" # 小于等于
                        }
                    }
                },
                {
                    "range":{
                        "目标时间字段":{
                        	# 距离现在2年前-18月之间
                            "gte": "now-2y/y",
                            "lt": "now-18m/m" # 小于
                        }
                    }
                },
                {
                    "range":{
                        "目标时间字段":{
                            "gte": "2023-02-15T12:53:59", # 不同的时间表示
                            "lt": "now",
                            # 当不用now-time的形式,选择时间戳,需要设置时间格式
                            "format": "yyyy-MM-dd hh:mm:ss"
                        }
                    }
                },
            ]

        }
    }
}


{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "目标字段":{
                            "query":"目标值"
                        }
                    }
                },
                {
                    "match":{
                        "目标字段":{
                            "query":"目标值"
                        }
                    }
                }
            ]
        }
    }
}

无分析查询

term查询

Term 查询,对输⼊不做分词。会将输⼊作为⼀个整体,在倒排索引中查找准确的词项,并且使⽤相关度算分公式为每个包含该词项的⽂档进⾏相关度算分。

{
  "query": {
    "term": {
      "目标字段": {
        "value":"目标值"
      }
    }
  }
}

需要注意的是,如果对于搜索字段增加keyword限制,那么就必须严格要求输入值完全等于目标值,否则查不到结果。

{
  "query": {
    "term": {
      "目标字段.keyword": {
        "value": "目标值"
      }
    }
  }
}

prefix查询

prefix 前缀查询
为了找到所有以 es开始的字段,可以使用简单的 prefix 查询:

{
    "query": {
        "prefix": {
            "目标字段": "es"
        }
    }
}

支持相似度操作的查询

这类查询是一些可以根据给定词项查找近似词项或文档的查询方式的集合。举例来说,假定需要找出包含crime的近似词项的文档,可以执行一个fuzzy查询。这类查询的另一个用途是提供类似“你是不是想找XX”的功能。比如要找出文档标题与输入文本相似的文档,可以使用more_like_this查询。一般来说,可以使用本类别下的某个查询来查找包含或给定输入内容近似的词项或字段的文档。
该类型的方法包含: fuzzy_like_this \ fuzzy_like_this_field \ fuzzy \ more_like_this \ more_like_this_field


{
    "query":{
        "fuzzy":{
            "目标字段":{
                "value": "目标值",
                "fuzziness" : 3, # 目标值长度在1-31;在3-525以上为3
            }
        }
    }
}

支持打分操作的查询

这是一组用于改善查询精度和相关度的查询方式,通过指定自定义权重因子或提供额外处理逻辑的方式来改变文档得分。这类查询的一个很好的例子是function_score查询。function_scroe查询可以使用函数,从而通过数学计算的方式改变文档得分。举个例子,如果希望离给定地理定位点越近的文档得分越高,则funciton_score查询可以帮助实现这个目的。
该类型的方法包含: boosting \ constant_score \ function_score \ indices等

{
	"query":{
		"boosting":{
			"postive":{
				"match_all":{}
			},
			"negative":{
				"term":{
					"avaliable": false
				}
			},
			"negative_boost":0.2
		}
	}
}


位置敏感查询

如果需要找出一组和其他单词保持一定举例的单词,比如“找出以下文档,同时包含mastering和elasticsearch且这两个单词相互临近,它们后面距离不超过3的位置包含second和editon单词”,这时就可以使用范围查询。不过需要之意,这些范围查询在将来版本的lucene库中将被移除,届时ES也不再提供支持。因为这些查询的开销很大,需要大量CPU资源才能保证处理正确。
这类查询的方法包含: match_phrase \ span_first \ span_first

结构敏感查询

最后一类查询时结构敏感数据(structure aware query)
包括: nested \ has_child \ has_parent \ top_children
一般来说,所有支持对文档结构进行索引并且不需要对文档数据进行扁平化处理的查询方式都可以归入此类。如果寻找一种查询方式,能够在子文档或嵌套文档中进行搜索,或者找属于给定父文档的子文档,就绪呀哦使用刚刚提及的查询方式之一。换句话说,如果需要处理文档中的数据关系,请使用这类查询。不过需要注意的时,尽管ES对数据之间的关系进行一定程度上的处理,但它并不是真正的关系数据库。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值