Elasticsearch教程 — Query DSL

查询语句核心语法部分

查询注意事项

  • text类型的查询都是基于分词后的词条查询的,例如"abcd"分词后"ab,cd"如果term查询"bc"就查不到。

query(查询)和filter(过滤)的区别

  • 查询语句可同时存在query和filter。
  • query的查询字段会进行相关性_score的计算,而filter仅仅用来筛选。
  • Elasticsearch会自动缓存常用的过滤器,以提高性能。

Compound queries(复合查询)

复合查询由其他复合查询或叶查询组合而成,以组合它们的结果和分数,改变它们的行为,或者从查询切换到过滤上下文。

bool(布尔查询)

布尔查询是最常用的组合查询,不仅将多个查询条件组合在一起,并且将查询的结果和结果的评分组合在一起。

bool相当于MySQL中的一个括号()

布尔查询支持的子查询类型共有四种,分别是:must,should,must_not和filter:

  • must,相当于MySQL中的and
  • should,相当于MySQL中的or
  • must_not,相当于MySQL中的and取反
  • filter过滤器,文档必须匹配该过滤条件,跟must子句的唯一区别是,filter不影响查询的score ,会缓存
POST _search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user.id" : "kimchy" }
      },
      "filter": {
        "term" : { "tags" : "production" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 20 }
        }
      },
      "should" : [
        { "term" : { "tags" : "env1" } },
        { "term" : { "tags" : "deployed" } }
      ],
      "minimum_should_match" : 1,
      "boost" : 1.0
    }
  }
}

boosting

为不喜欢的查询减分

其参数有如下几个:

  • positive(必需,查询对象)查询语句。
  • negative(必需,查询对象)降低分数的匹配查询。匹配的文档评分,由positive查询的原始评分乘以negative_boost值,就得到了最终评分。
  • negative_boost(必需,浮点数)0-1之间的浮点数,用于降低分数的比例。
    GET /_search
    {
    "query": {
      "boosting": {
        "positive": {
          "term": {
            "text": "apple"
          }
        },
        "negative": {
          "term": {
            "text": "pie tart fruit crumble tree"
          }
        },
        "negative_boost": 0.5
      }
    }
    }

constant_score

恒定分数查询

GET /_search
{
  "query": {
    "constant_score": {
      "filter": { # (必需,查询对象)过滤查询
        "term": { "user.id": "kimchy" }
      },
      "boost": 1.2 # (可选,浮点数)置为每个返回文档的分数,默认1.0
    }
  }
}

dis_max

dis_max 查询只使用最佳匹配查询条件的分数,

  • queries,返回的文档必须与这些查询中的一个或多个匹配。如果一个文档匹配多个查询,Elasticsearch 使用最高的相关性分数
  • tie_breaker,(可选,浮点数)0-1之间,默认0.0,用于增加的评分。
GET /_search
{
  "query": {
    "dis_max": {
      "queries": [ # (必需,查询对象数组)包含一个或多个查询子句,
        { "term": { "title": "Quick pets" } }, # 查询字句,假设C1=1.3
        { "term": { "body": "Quick pets" } }, # 查询字句,假设C2=1.8
        { "term": { "content": "Quick pets" } } # 查询字句,假设C3=1.1
      ],
      "tie_breaker": 0.2
    }
  }
}

无dis_max查询时的评分,大致应该是C1+C2+C3的评分
有dis_max评分大致计算:C2+(C1+C3)*tie_breaker

function_score(打分函数)

function_score 会在主查询query结束后对每一个匹配的文档进行一系列的重新打分操作,能够对多个字段一起进行综合评估,并且能够使用filter将结果划分为多个子集,并为每个子集使用不同的加强函数。

需要注意的是:不论我们怎么自定义打分,都不会改变原始query的匹配行为,我们自定义打分,都是在原始 query 查询结束后,对每一个匹配的文档进行重新算分。

最终结果的 _score 即 result_score 的计算过程如下:

  • 跟原来一样执行query并且得到原来的query_score
  • 执行设置的自定义打分函数,并为每个文档得到一个新的分数,本文记为func_score
  • 最终结果的分数result_score等于query_scorefunc_score按某种方式计算的结果(默认是相乘)。

最终的分数result_score是由query_scorefunc_score进行计算而来,计算方式由参数boost_mode定义:

  • multiply : 相乘(默认),result_score = query_score * function_score
  • replace : 替换,result_score = function_score
  • sum : 相加,result_score = query_score + function_score
  • avg : 取两者的平均值,result_score = Avg(query_score, function_score)
  • max : 取两者之中的最大值,result_score = Max(query_score, function_score)
  • min : 取两者之中的最小值,result_score = Min(query_score, function_score)

function_score 提供了以下几种打分的函数:

  • weight : 加权。
  • random_score : 随机打分。生成 [0, 1) 之间均匀分布的随机分数值
  • field_value_factor : 使用字段的数值参与计算分数。
  • decay_function : 衰减函数 gauss, linear, exp 等。
  • script_score : 自定义脚本打分。
# 使用示例:
GET /_search
{
  "query": {
    "function_score": { # 打分函数
      "query": { "match_all": {} }, # 原始query的匹配
      "boost": "5", # 用以提高整个查询权重
      "functions": [ # 当有多个打分函数时,需使用functions,当只有一个时,可省略
        { # 打分函数1:可以理解成,weight*随机数
          "weight": 23, # 加权值,默认值是1.0,也可以理解每个打分函数都有一个 weight: 1.0
          "filter": { "match": { "test": "bar" } }, # 通过 filter 去限制 weight 的作用范围
          "random_score": { # 随机打分,生成0-1之间的随机数,本示例中random_score在0-23之间
            "seed": 10,
            "field": "_seq_no"
          } 
        },
        { # 打分函数2
          "weight": 42 # 加权数
          "filter": { "match": { "test": "cat" } }, # 通过 filter 去限制 weight 的作用范围
        },
        { # 打分函数3:衰减函数,
          "weight": 1.0, #  默认加权 1.0倍
          "exp": { # exp指数函数算法
            "ctime": { # 时间衰减
              "origin": 1649582870, # 当前时间戳
              "scale": 4320000, # 50天内衰减
              "offset": 800, # 从多长时间后开始衰减
              "decay": 0.1 // 最低衰减值
            }
          }
        },
        { # 打分函数4:使用字段值计算,此方法可以理解成:1.0*log1p(1.2*doc['weight'].value)
          "weight": 1.0, #  默认加权 1.0倍
          "field_value_factor": { 
            "field": "weight", # 参与计算的字段
            "modifier": "log1p", # 计算函数,有十来个函数可以查看文档,示例中:log1p(1.2*doc['weight'].value),其实和script_score计算差不多,只不过效率更高
            "factor": 1.2, # 函数的调节用的参数,factor>1会提升效果,factor<1会降低效果
            "missing": 1   # 若 weight 字段不存在,则默认为1
          }
        },
        { # 打分函数5:使用脚本来自定义
          "script_score": {
            "source": "params.a / Math.pow(params.b, doc['my-int'].value)",
            "params": {"a": 5,"b": 1.2},
          }
        }
      ],
      "score_mode": "avg", # 参数 score_mode 指定多个打分函数如何组合计算出新的分数,avg求平均
      "min_score": 2 # 为了排除掉一些分数太低的结果,我们可以通过 min_score 参数设置最小分数阈值
      "boost_mode": "multiply", # 就是把原始的 query_score 与新的 func_score 计算就得到了最终的 _score 分数
      "max_boost": 42, # 为了避免新的分数的数值过高,可以通过 max_boost 参数去设置上限
    }
  }
}

注意:这里的重新打分时,如果都提供了weight这个参数,且score_mode=avg,那么计算最终的func_score时,应该是加权平均数(例如:打分函数1的weight=2,算出来的值是3,打分函数2的weight=5,算出来的值是2,加权平均数=(2*3+5*2)/(2+5)

其他文章:
ES 自定义打分 Function score query

Full text queries(全文查询)

全文查询使您能够搜索分析器分析过后的文本字段,例如内容正文。使用在索引期间应用于字段的相同分析器处理查询字符串。

intervals

为了更加简单灵活的控制查询时字符串在文本中匹配的距离先后顺序,官方在es7.0引入了intervals query,用户可单一或者组合多个规则集合在某一个特定的text field上进行操作。

POST _search
{
  "query": {
    "intervals" : { # intervals查询关键字
      "my_text" : { # (必需,规则对象)要搜索的text字段。
        "all_of" : { # 匹配规则,有效规则包括:match、prefix、wildcard、fuzzy、all_of、any_of
          "ordered" : true, # all_of规则参数(可选,布尔值)如果true,规则产生的间隔应按指定的顺序出现。默认为false.
          "intervals" : [ # all_of规则参数(必需,规则对象数组)要组合的规则数组。
            { # 子规则1
              "match" : {
                "query" : "my favourite food",
                "max_gaps" : 0,
                "ordered" : true
              }
            },
            { # 子规则2
              "any_of" : {
                "intervals" : [
                  { "match" : { "query" : "hot water" } },
                  { "match" : { "query" : "cold porridge" } }
                ]
              }
            }
          ]
        },
        "boost" : 2.0,
        "_name" : "favourite_food"
      }
    }
  }
}

match 【重要】

match查询是执行全文搜索的标准查询,包括用于模糊匹配的选项。

GET /_search
{
  "query": {
    "match": { # match关键字
      "message": { # (必需,对象)要搜索的字段。
        "query": "this is a test", # 要查询的内容
        "analyzer":{...}, # (可选,字符串)分析器
        "operator":"", #(可选,字符串)用于解释query值中文本的布尔逻辑。有效值为:OR AND
        "fuzziness":"", #(可选,字符串)允许匹配的最大编辑距离。
        "max_expansions":50, # (可选,整数)查询将扩展到的最大术语数。默认为50
        "prefix_length":0, #(可选,整数)用于模糊匹配的起始字符数保持不变。默认为0
        "fuzzy_transpositions":0, #可选,布尔值)如果true,模糊匹配的编辑包括两个相邻字符的换位(ab → ba)默认为true
        "fuzzy_rewrite":"", #(可选,字符串)用于重写查询的方法。
        "lenient":false #(可选,布尔值)如果,则忽略true基于格式的错误
      }
    }
  }
}

match_bool_prefix

查询处理流程:

  • 对查询的内容进行分词;
  • 然后构造bool查询;
  • 对每个分词(除了最后一个分词)使用term查询;
  • 但对最后一个分词采用prefix查询。
GET /_search
{
  "query": {
    "match_bool_prefix": { # 查询关键词
      "message": { # 查询字段
        "query": "quick brown f", # 被查询的词,被分为3个词quick、brown、f。其中quick与brown使用term查询,p使用prefix查询
        "analyzer": "keyword" # 指定分析器
      }
    }
  }
}

match_phrase

match_phrase查询分析文本,并从分析的文本中创建短语查询。

GET /_search
{
  "query": {
    "match_phrase": {
      "message": {
        "query": "quick brown fox",
        "analyzer": "my_analyzer"
      }
    }
  }
}

对于匹配了短语"quick brown fox"的文档,下面的条件必须为true:

  • quick、brown和fox必须全部出现在某个字段中。
  • brown的位置必须比quick的位置大1。
  • fox的位置必须比quick的位置大2。

如果以上的任何一个条件没有被满足,那么文档就不能被匹配。

match_phrase_prefix

match_phrase_prefix和match_phrase是相同的,除了它允许文本中最后一项使用前缀匹配。

GET /_search
{
  "query": {
    "match_phrase_prefix": {
      "message": {
        "query": "quick brown f" # 注意,分词的最后一项f使用前缀匹配
        "max_expansions":50, # 这里可以理解前缀查询f需在多少个词内查询到
        "analyzer":ik  
      }
    }
  }
}

multi_match

multi_match查询提供了一个简便的方法用来对多个字段执行相同的查询。

GET /_search
{
  "query": {
    "multi_match" : { # 关键字
      "query":      "brown fox", # 查询字符串,经分析器处理后
      "type":       "best_fields", # 处理类型
      "fields":     [ "subject", "message" ], # 待处理的字段列表
      "tie_breaker": 0.3 
    }
  }
}

combined_fields

支持查询多个字段,比如文章的标题、正文、描述,也可以使用^字符提升某个字段的权重,同时也支持通配符。

GET /_search
{
  "query": {
    "combined_fields" : {
      "query":      "database systems",
      "fields":     [ "title", "abstract", "body"],
      "operator":   "and"
    }
  }
}

query_string

query_string是使用查询解析器来解析其内容的查询。
官方查询字符串语法

GET /_search
{
    "query": {
        "query_string" : {
            "default_field" : "content", # 默认字符串
            "query" : "this AND that OR thus" # 查询语法
        }
    }
}

simple_query_string

相比query_string,不支持 AND OR NOT, 但会当作字符串处理,Term 之间默认的关系是 OR, 可以指定 Operator
+替代AND,|替代OR,-替代NOT

Geo(地理查询)

Elasticsearch 支持两种类型的地理数据:geo_point字段,支持纬度/经度;geo_shape字段,支持点、线、圆、多边形、多多边形等。

geo_bounding_box(矩形内的点的文档)

geo_distance(中心点指定距离内的文档)

geo_polygon(多边形内的文档)

geo_shape(相交、包含、不想交的形状)

Shape queries(形状查询)

Elasticsearch 支持索引任意二维(非地理空间)几何的能力,这使得绘制虚拟世界、体育场馆、主题公园和 CAD 图表成为可能。

shape

以下是可用空间关系运算符的完整列表:

  • INTERSECTS-(默认)返​​回shape字段与查询几何相交的所有文档。
  • DISJOINT- 返回其shape字段与查询几何没有共同之处的所有文档。
  • WITHIN- 返回其shape字段在查询几何范围内的所有文档。
  • CONTAINS- 返回其shape字段包含查询几何的所有文档。
    GET /example/_search
    {
    "query": {
      "shape": {
        "geometry": {
          "shape": {
            "type": "envelope",
            "coordinates": [ [ 1355.0, 5355.0 ], [ 1400.0, 5200.0 ] ]
          },
          "relation": "within"
        }
      }
    }
    }

Joining queries(加入查询)

在像 Elasticsearch 这样的分布式系统中执行完整的SQL风格的连接是非常昂贵的。相反,Elasticsearch 提供了两种形式的连接,旨在水平扩展

nested(嵌套查询)

has_child and has_parent(有子查询,有父查询)

# 定义nested
PUT /my-index-000001
{
  "mappings": {
    "properties": {
      "obj1": {
        "type": "nested" # 这里类型设置为nested
      }
    }
  }
}
# 使用nested查询
GET /my-index-000001/_search
{
  "query": {
    "nested": { # 查询关键字
      "path": "obj1",  # 您希望搜索路径嵌套对象
      "score_mode": "avg", # 设置内部children匹配影响parent文档。默认是avg,但是也可以设置为sum、min、max和none
      "query": { # 查询语法
        "bool": {
          "must": [
            { "match": { "obj1.name": "blue" } },
            { "range": { "obj1.count": { "gt": 5 } } }
          ]
        }
      }
    }
  }
}

Match all(匹配所有)

match_all(匹配所有文档)

GET /_search
{
  "query": {
    "match_all": { "boost" : 1.2 }
  }
}

match_none(不匹所有文档)

GET /_search
{
  "query": {
    "match_none": {}
  }
}

Span queries(范围查询)

span_containing

span_field_masking

span_first

span_multi

span_near

span_not

span_or

span_term

span_within

Specialized queries(专业查询)

distance_feature

more_like_this(相似度查询)

percolate

rank_feature

script

script_score

wrapper

pinned

Term-level queries(术语级查询)

根据结构化数据中的精确值查找文档。结构化数据的示例包括日期范围、IP 地址、价格或产品 ID。与全文查询不同,词级查询不分析搜索词。相反,术语级别的查询与存储在字段中的确切术语相匹配。

exists (包含字段索引值的文档),可以理解成MySQL中的is not null

# 查找指定字段存在的文档
GET /_search
{
  "query": {
    "exists": {
      "field": "user" # 必须,指定的字段,此字段必须包含值。不存在:null和[],存在:"","-",[null,"foo"]
    }
  }
}

fuzzy (包含与搜索词相似的词的文档)

# 为了查找相似的术语,fuzzy查询会在指定的编辑距离内创建一组搜索术语的所有可能变体或扩展。然后查询返回每个扩展的精确匹配。
GET /_search
{
  "query": {
    "fuzzy": { 
      "user.id": { # 必须,要搜索的字段
        "value": "ki", # 必须,待搜索的值
        "fuzziness": "AUTO", # 允许匹配的最大编辑距离
        "max_expansions": 50, # 创建的最大变体数。默认为50
        "prefix_length": 0, # 创建扩展时保持不变的起始字符数。默认为0
        "transpositions": true, # 是否包括两个相邻字符的换位(ab → ba)。默认为true
        "rewrite": "constant_score" # 重写查询的方法。
      }
    }
  }
}

ids (查_id值)

# 根据文档的 ID 返回文档。此查询使用存储在_id字段中的文档 ID
GET /_search
{
  "query": {
    "ids" : {
      "values" : ["1", "4", "100"] # 必需,字符串数组,文档_id数组
    }
  }
}

prefix (查前缀)

# 包含特定前缀的文档
GET /_search
{
  "query": {
    "prefix": { 
      "user.id": { # 字段名
        "value": "ki" # 待搜索的值
      }
    }
  }
}

range (范围查询) 理解成MySQL中的between

# 数字或时间范围匹配
GET /_search
{
  "query": {
    "range": { # 范围查询
      "age": { # 字段名
        "gte": 10, # 操作符 gt(>) gte(>=) lt(<) lte(<=)
        "lte": 20,
        "format": "yyyy/MM/dd", # 用于转换date查询中值的日期格式
        "time_zone": "", # 指定时区
        "boost": 2.0 # 增减查询参数
      }
    }
  }
}

regexp (正则表达式匹配)

# 正则表达式
GET /_search
{
  "query": {
    "regexp": {
      "user.id": { # 要搜索的字段
        "value": "k.*y", # 正则表达式,要提高性能,请避免使用通配符模式,例如.*或 .*?+,而没有前缀或后缀
        "flags": "ALL", # 正则表达式启用可选运算符
        "case_insensitive": true, # 是否区分大小写的匹配
        "max_determinized_states": 10000,
        "rewrite": "constant_score" # 重写查询的方法
      }
    }
  }
}

term (精确匹配,除了text类型的字段),可以理解成MySQL中的等于(=)

# 精确查询
# 避免term对text字段使用查询
# 默认情况下,text作为analysis 的一部分,Elasticsearch 会更改字段的值。这会使查找text字段值的精确匹配变得困难。要搜索text字段值,请改用match查询。
GET /_search
{
  "query": {
    "term": {
      "user.id": { # 字段
        "value": "kimchy", # 值
        "boost": 1.0 # 权重
      }
    }
  }
}

terms (精确匹配多个)

# 可以理解成MySQL中的in查询
# 同term查询,唯一不同的就是可以设置多个值
GET /_search
{
  "query": {
    "terms": { 
      "user.id": [ "kimchy", "elkbee" ], # 匹配多个值
      "boost": 1.0
    }
  }
}

terms_set (精确匹配多个,可定义最少匹配数)

# 同terms查询,但可以定义最少匹配数
GET /job-candidates/_search
{
  "query": {
    "terms_set": {
      "programming_languages": {
        "terms": [ "c++", "java", "php" ],
        "minimum_should_match_field": "required_matches",
        "minimum_should_match_script": {
          "source": "Math.min(params.num_terms, doc['required_matches'].value)"
        },
        "boost": 1.0
      }
    }
  }
}

wildcard (通配符查询)

GET /_search
{
  "query": {
    "wildcard": {
      "user.id": { # 字段
        "value": "ki*y", # 通配符的值
        "boost": 1.0, # 权重
        "rewrite": "constant_score" # 改变查询行为,专业人士使用,此参数的值会影响搜索性能和相关性
      }
    }
  }
}

相关文章

此处评论已关闭