ES之DSL简单查询
【摘要】 DSL全称Domain Specific Language,即领域特定语言,ES基于JSON提供完整的DSL来定义查询。因为一些工作需要,后续对DSL做了一些了解,感觉如果结合ES一起进行使用,练习会更好。首先是简单查询,类似于sql中的条件匹配,且只有一个条件# match_all 全量查询,无匹配条件。 类似sql无where{ "query":{ "match_a...
DSL全称Domain Specific Language,即领域特定语言,ES基于JSON提供完整的DSL来定义查询。因为一些工作需要,后续对DSL做了一些了解,感觉如果结合ES一起进行使用,练习会更好。
首先是简单查询,类似于sql中的条件匹配,且只有一个条件
# match_all 全量查询,无匹配条件。 类似sql无where
{
"query":{
"match_all":{
}
}
}
# match 针对某一个字段进行的关键字匹配 。 类似sql中的contanins
{
"query":{
"match":{
"username":"小明"
}
}
}
# term 精确匹配,针对某一个字段的值进行精确匹配 。 类似sql中的username=
{
"query":{
"term":{
"username":"小明"
}
}
}
#terms 精确匹配多个值,针对某一个字段的值进行精确匹配。 类似sql中的 in ("")
{
"query":{
"terms":{
"username":["小明","小红"]
}
}
}
# wildcard 通配符匹配,针对某一个字段的值进行模糊匹配。 类似sql中的like
{
"query":{
"wildcard":{
"username": "*小明*"
}
}
}
# prefix 前缀查询,针对某一个字段的值进行前缀匹配。类似sql中的like '%x'
# todo 后续补充:这里使用的时候发现了一些问题,例如查不出来数据,即使只匹配一个开头字母,暂未确定什么原因,暂记,后续补充,大概率是字段的类型有关
{
"query":{
"prefix":{
"username": "王小"
}
}
}
# fuzzy 模糊查询,针对某一个字段的值进行模糊匹配,这个sql中就没有了,比喻的话就是相似度匹配。fuzziness为可允许的错误的数,也可设置为Auto
# todo 后续补充:这里使用的时候,可能还涉及其他的干扰,例如一个词允许的错误次数,例如,一个字段只有3个字,即使fuzziness设置了3,但是如果有两个字错误,依旧是搜索不出来的, 但是如果字段的数比较多的情况,又可以搜出来,所以应该是有其他的限制
{
"query":{
"fuzzy":{
"username": {
"value":"王大明",
"fuzziness":1
}
}
}
}
#regexp 正则匹配,针对某一个字段进行正则匹配,sql中没有,跟普通的正则差不多。
{
"query":{
"regexp":{
"username": "^[a-zA-Z]{3}$"
}
}
}
其次是稍微复杂的一点的场景,例如需要多个条件同时匹配的场景,类似于where的and or连接,用的较多,可以把上述简单合并一起使用。
# bool 布尔查询,联合多个简单子查询得出结果,需要结合3个关键连接词使用must、must_not、should、filter。
# must类比sql中的and。 must中列举的多个条件都要满足
# must_not类比sql中的 and not。 must_not中列举的多个条件都要不满足
# should类比sql中的or。 should中列举的多个条件任意一个满足即可
# filter类比sql中的and。 filter中列举的多个条件都要满足。
// todo 后续补充:filter和must是一样的,为什么要有两个呢,这里涉及分数算法,这个概念暂时还不太懂,后续了解了补充。反正filter和must_not不涉及得分,可以优先使用,效率更高一点。
{
"query":{
"bool":{ # 布尔查询, 可以嵌套多个关键连接词, 关键连接词可以嵌套多个条件匹配,连接词之间最后用and连接。
"must": [{"match":{"username":"小明"}},{"term":{"sex":"男"}}],
"must_not": [{"match":{"username":"小明"}},{"term":{"sex":"男"}}],
"should": [{"match":{"username":"小明"}},{"term":{"sex":"男"}}],
"filter": [{"match":{"username":"小明"}},{"term":{"sex":"男"}}]
}
}
}
补充:should与must、filter公用会导致预期输出不一致的情况。这个有点是意料之外的,按照开发的逻辑去进行条件筛选,但是should的时候,这种逻辑却行不通了
以下举例进行说明:
// 举例说明,我需要查询一个姓张或者姓李的同学 且需要性别是男的
按照逻辑,应该就是 should任意满足姓氏 + must 满足 行性别
{
"query": {
"bool": {
"should": [
{
"regexp": {
"request": "张.*"
}
},
{
"regexp": {
"request": "李.*"
}
}
],
"must": [
{
"term": {
"gender": "男"
}
}
]
}
},
"_source": [
"@timestamp",
"name",
"gender"
]
}
# 猜一下上述代码片段输出什么? 1.姓张和姓李 且有小字 2.姓张和姓李所有同学 3.名字有小的所有同学
# 答案是3,所有名字有小的同学。
# 猜测原因 1.should和must之间的连接是or 2.跟执行should或者must的顺序有关
# 测试结论: 1.如果or的话,只需要验证一下3个毫无关系的名字即可, 例如叫must王小明 should张飞 should李晓,验证结论 无效,只输出了王小明 2.如果是跟顺序有关, 调换must和should的顺序,无效,输出与为调换前一致
# todo 暂时未定位到什么原因,结果大佬的文章分析,应该和DSL的解析有关,但是对于具体细节并没有说太多。
# 不过对于相关的解决办法目前倒是明确的,就是使用嵌套的方法,使用bool + must +bool进行嵌套,达到预期的数据输出,调整后代码如下:
{
"query": {
"bool": {
"must": [ # 新增must嵌套,外层连接
{
"bool": { # 每一组筛选 使用bool进行判断 多个bool组成一个大的must
"should": [
{
"regexp": {
"name": "张.*"
}
},
{
"regexp": {
"name": "李.*"
}
}
]
}
},
{
"bool": {
"must": [
{
"term": {
"gender": "男"
}
}
]
}
}
]
}
},
"_source": [
"@timestamp",
"name",
"gender"
]
}
以上基本上就是经常使用的一些语法查询,对于一些简单的查询应该足够了,不过工作中可能还会涉及更复杂的场景,例如分页、排序、范围查询、时间查询、聚合查询、多重嵌套条件等等。
# range、sort、from、_source等常用的语法关键字列举。避免麻烦,相关的一些字段就一起列出来了,就不一一列举了
{
"query": {
"bool": { # 布尔查询
"filter": [ #过滤
{
"range": { #范围查询
"@timestamp": {
"gt": "2024-03-05 17:00:00", #大于 当前时间可用now。 可进行运算如 now-1h:当前时间减少一个小时
"lt": "2024-03-05 18:00:00",# 小于 m h d w y 分别代表分时天周年
"time_zone": "+08:00", # 位置时间 非必填
"format": "yyyy-MM-dd HH:mm:ss" #时间格式 非必填
}
}
}
],
"must_not": [
{
"exists": { #查询结果是否包含某一类字段值,这里是过滤字段不是值, 感觉很少用到
"field": "area"
}
}
]
}
},
"sort": [ #排序
{
"timestamp": { # 字段名
"order": "asc" #升序降序
}
}
],
"from": 1, #页码
"size": 3, #页条数
"_source": [ #返回字段
"@timestamp",
"body_bytes_sent",
"request",
"response"
]
}
剩下的话,还剩一个聚合关键字aggs。类比于sql中的group by having函数。使用上就更加复杂了,这里就做简单描述了。todo 后续就机会再进行补充。
# aggs函数,就是将筛选出来的数据再次就行聚合分组,可以用来计算总数,平均数,最大值等等
# 直接类比sql的where + group by having。我觉得十分类似,先bool后aggs
{
"query": {
"bool": {
"filter": [
{
"range": {
"@timestamp": {
"gt": "2024-03-05 17:00:00",
"lt": "2024-03-05 18:00:00",
"time_zone": "+08:00",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
]
}
},
"aggs": { # 聚合函数
"NAME": { # 聚合的字段名,任意取即可
"terms": { # 按照字段进行聚合分组
"field": "request", # 分组的字段
"size":3 # 保留的行数
}
}
}
}
上述比较重要的就是terms,表明是通过字段进行分组,除了terms,还有其他的字段,作用各不相同
terms聚合:按字段进行分组,并统计每个分组的文档数量。
date_histogram聚合:按时间间隔对日期字段进行分组,并统计每个时间间隔内的文档数量。
range聚合:将字段的值划分为不同的范围,并统计每个范围内的文档数量。
histogram聚合:将数值字段的值划分为不同的区间,并统计每个区间内的文档数量。
avg聚合:计算数值字段的平均值。
sum聚合:计算数值字段的总和。
min聚合:找到数值字段的最小值。
max聚合:找到数值字段的最大值。
cardinality聚合:计算字段的基数(不重复值的数量)。
top_hits聚合:返回每个分组中的顶部文档。
extended_stats聚合:计算数值字段的统计信息,包括平均值、标准差、最小值、最大值等。
percentiles聚合:计算数值字段的百分位数。
geo_distance聚合:按地理距离对地理坐标字段进行分组,并统计每个距离范围内的文档数量。
filter聚合:根据指定的过滤条件对文档进行聚合。
nested聚合:在嵌套的文档结构中进行聚合操作。
value_count聚合:计算某个字段的值的数量。
stats聚合:计算数值字段的统计信息,包括平均值、总和、最小值、最大值和文档数量。
scripted_metric聚合:使用自定义脚本计算聚合结果。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)