ES基本查询

  • 基本匹配模式:

  ES支持的查询语法中的匹配模式比较多,主要包括以下几种:

  1. term查询:精确匹配,不会分词。
  2. terms查询:精确匹配多个值。
  3. match查询:对字段进行全文本搜索并分词,允许模糊匹配。
  4. match_phrase查询:对字段进行短语全文本搜索,要求匹配的词条必须按照原始文本顺序相邻出现。
  5. prefix查询:对字段进行前缀搜索。
  6. regexp查询:使用正则表达式匹配。
  7. wildcard查询:使用通配符进行模糊匹配。
  8. range查询:对数值、日期等范围进行匹配,包括大于、小于、大于等于、小于等于、等于等。
  9. exists查询:匹配指定字段存在的文档。
  10. bool查询:将其他查询进行逻辑组合,包括must、must_not、should、filter等。
  11. nested查询:查询嵌套文档中的字段。
  12. fuzzy查询:支持单词拼写错误的匹配。
  13. geo查询:查询地理坐标范围内的文档。
  14. ids查询:根据指定的文档ID进行匹配。
  15. span查询:一系列用于匹配词语之间距离或顺序的查询,包括span_term、span_multi等。

  以上是ES支持的一些常见的查询语法中的匹配模式,不同的查询语法和匹配模式可以组合使用,以实现更复杂的查询。

 

  给出每一个匹配模式的示例:

  1. term查询:
  { "query": { "term": { "age": 18 } } }
  1. terms查询:
  { "query": { "terms": { "age": [18, 19] } } }
  1. match查询:
  { "query": { "match": { "title": "elasticsearch" } } }
  1. match_phrase查询:
  { "query": { "match_phrase": { "content": "elasticsearch tutorial" } } }
  1. prefix查询:
  { "query": { "prefix": { "name": "jo" } } }
  1. regexp查询:
  { "query": { "regexp": { "name": "joh?n" } } }
  1. wildcard查询:
  { "query": { "wildcard": { "name": "j*hn" } } }
  1. range查询:
  { "query": { "range": { "age": { "gte": 18, "lte": 25 } } } }
  1. exists查询:
  { "query": { "exists": { "field": "age" } } }
  1. bool查询:
{ "query": { "bool": { "must": [ { "match": { "title": "elasticsearch" } }, { "match": { "content": "tutorial" } } ] } } }

这样写也正确:
{ "query": { "must": [ { "match": { "name": "elasticsearch" } }, { "match": { "content": "搜索引擎" } } ] } } 

举个bool查询的复杂示例:
{
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "should": [
              {
                "match": {
                  "title": {
                    "query": "elasticsearch"
                  }
                }
              },
              {
                "match": {
                  "content": {
                    "query": "elasticsearch"
                  }
                }
              }
            ]
          }
        },
        {
          "bool": {
            "should": [
              {
                "match": {
                  "title": {
                    "query": "tutorial"
                  }
                }
              },
              {
                "match": {
                  "content": {
                    "query": "tutorial"
                  }
                }
              }
            ]
          }
        },
        {
          "bool": {
            "should": [
              {
                "match": {
                  "title": {
                    "query": "beginner"
                  }
                }
              },
              {
                "match": {
                  "content": {
                    "query": "beginner"
                  }
                }
              }
            ]
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "category": {
              "query": "A"
            }
          }
        }
      ],
      "filter": {
        "term": {
          "author": "John"
        }
      },
      "minimum_should_match": 2
    }
  }
}
  这个查询使用了三个bool查询套嵌,每个bool查询都使用should子句将title和content字段与关键词匹配,然后用must子句将三个bool查询组合起来,要求至少匹配两个关键词。使用must_not子句排除类别为A的文章,使用filter子句限制作者为John。

  1. nested查询:
  { "query": { "nested": { "path": "comments", "query": { "match": { "comments.author": "john" } } } } }
  1. fuzzy查询:
  { "query": { "fuzzy": { "name": { "value": "john", "fuzziness": 2 } } } }
  1. geo查询:
  { "query": { "bool": { "must": { "match_all": {} }, "filter": { "geo_distance": { "distance": "10km", "pin.location": { "lat": 40, "lon": -70 } } } } } }
  1. ids查询:
  { "query": { "ids": { "values": ["1", "2", "3"] } } }
  1. span查询:
  { "query": { "span_near": { "clauses": [ { "span_term": { "field": "quick" } }, { "span_term": { "field": "brown" } }, { "span_term": { "field": "fox" } } ], "slop": 3, "in_order": false } } }

  简单地解释一下这些示例的含义:

  1. term查询:查询age字段的值为18的文档,这里不会分词,只对整个字段进行精确匹配。

  2. terms查询:查询age字段的值为18或19的文档,这里可以同时对多个值进行匹配。

  3. match查询:对title字段进行全文本搜索并分词,查找包含单词"elasticsearch"的文档。
  1. match_phrase查询:对content字段进行短语全文本搜索,要求匹配的词条必须按照原始文本顺序相邻出现,查找包含短语"elasticsearch tutorial"的文档。

  2. prefix查询:查询name字段以"jo"开头的文档。

  3. regexp查询:使用正则表达式查找name字段中匹配"joh?n"模式的文档,这里"?"表示匹配前面字符0次或1次。

  4. wildcard查询:使用通配符查找name字段中匹配"jhn"模式的文档,这里""表示匹配0个或多个任意字符。

  5. range查询:查询age字段大于等于18小于等于25的文档。

  6. exists查询:查询存在age字段的文档。

  7. bool查询:将两个match查询组合,必须同时满足两个条件才能匹配。

  8. nested查询:查询包含特定作者("john")的一篇文章的评论。

  9. fuzzy查询:查找name字段拼写跟"john"相似的文档,这里"fuzziness"表示允许编辑的最大距离为2(即可以通过2次编辑变成"john")。

  10. geo查询:查找距离经纬度为(40,-70)坐标不超过10km的地理位置文档。

  11. ids查询:查找ID为1、2、3的文档。

  12. span查询:查询包含短语"quick brown fox"的文档的数量,这里"slop"表示相邻单词的最大距离为3。

 

  • filtermust都是bool查询中的查询子句,它们的作用不同:

filter查询与must查询类似,都用于对查询进行过滤和匹配。但不同的是,filter不计算查询得分并且可以使用缓存,它是用于过滤大量数据的一个非常有效的机制,通常用于在水平方向上增加查询效率。它可以和其他查询子句(例如mustshouldmust_not)一起使用,如果多种查询子句一起使用,则必须满足所有的mustfilter语句,而should则只需满足其任意一个。例如:

 

{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "price": {
            "gte": 100,
            "lte": 1000
          }
        }
      },
      "must": [
        {
          "match": {
            "title": "elasticsearch"
          }
        }
      ]
    }
  }
}

  上述查询用到了filtermust两个查询子句,它首先使用filter子句过滤出价格在[100,1000]区间的文档,然后再在这个结果中使用must查询子句匹配title字段中的"elasticsearch",从而得到我们需要的结果。

 

 

must查询用于执行多个查询的布尔“与”操作,并结合各查询子句的结果进行打分排序。这意味着必须满足must查询子句中的所有条件才能使文档获得更高的得分并返回。例如:

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "user": "kimchy"
          }
        },
        {
          "match": {
            "title": "elasticsearch"
          }
        }
      ]
    }
  }
}

上述查询中,两个match查询子句的查询结果都必须为真,才能匹配到符合条件的文档,两个查询条件是“与”的关系。在实际使用中,我们要根据不同的需求选择不同的查询子句来处理查询,尽可能提高查询效率和准确性。如果在查询的大多数操作中使用了filter,通常推荐在其他查询中使用`must,这样可以带来更快的查询性能。

 

 

  • 相关性得分计算在 Elasticsearch 中非常复杂,在这里简单介绍一下简单模式下的得分计算方法。

match查询为例,需要考虑的因素有文档中查询关键字在也出现的域的数量、文档中出现查询关键字的频率、查询关键字在一个域中的重要性、查询关键字在所有文档中出现的频率等。Elasticsearch为每个索引分配一个默认的相关性评分器,该评分器使用了基于TF-IDF(词频-逆文档频率)算法的BM25算法计算文档得分。BM25考虑了词项的频度、文档长度等因素,并通过对文档长度进行归一化处理来对文档的“重要性”进行加权。

简而言之,BM25算法计算文档得分的大致方式如下:

  1. 计算查询中每个词的TF-IDF得分
  2. 对于每个查询词,则通过考虑所有包含这个词的文档计算文档频率(IDF)
  3. 计算查询与文档中每个匹配的词项之间的匹配度(term frequency)。匹配度用于调整词项的重要性,即一些重要的关键词应该有更高的权值。
  4. 计算文档得分,再将文档得分与其他相关性评分算法产生的得分相加,获得最终的文档评分。

  BM25算法实现了一种有效地对文档打分的方法,能够准确地反映查询与文档之间的相关性。通过修改算分公式和相关性评分器,甚至可以更好地优化该算法,以满足不同场景的需求。

假设我们有一个文档,它包含下面这些字段:

{ "title":"Elasticsearch 入门", "content":"这是一篇关于 Elasticsearch 入门的文章,用以介绍 Elasticsearch 的基本特性、查询语法和常见应用场景" }

 

假设我们进行下面这个查询:

GET /my_index/_search { "query": { "bool": { "should": [ { "match": { "title": "elasticsearch" } }, { "match": { "content": "elasticsearch" } } ] } }, "sort": { "_score": "desc" } }

 

Elasticsearch会计算所有匹配到的文档与查询之间的相关性得分。假设在上面的示例中,"elasticsearch"在title字段和content字段中都出现了一次,那么我们可以使用BM25算法来计算相关性得分。

假设我们参数配置为k1 = 1.2、b = 0.75、avgdl=9、idf=1、tf=1在。那么对上述文档进行评分时,BM25算法的基本公式如下:

score(D,Q) = IDF × (tf(Q_i,D) × (k1 + 1)) / (tf(Q_i,D) + k1 * (1 - b + b * (doc_len/avgdl)))

其中score(D,Q) 表示文档D和查询Q之间的相关得分,IDF是词项的逆向文档频率,tf(Q_i,D) 表示词项Q_i出现在文档D中的频率,k1 和 b 是两个参量,avgdl 表示所有文档的平均长度。

我们可以通过填入合适的参数来计算该文档的相关得分,得到最终的评分结果。在实际中,Elasticsearch 会根据文档的长度、查询的倒入、各种噪声词筛选、参数调整等多种因素对得分公式进行优化,结果的细节也比简化版更加复杂,涉及到更多的数学和算法知识。

  • IDF(Inverse Document Frequency)表示逆文档频率,用于衡量一个词的重要程度。IDF 值越大,则表示该词的重要性越高,因此文档中包含该词的相关得分就越高。

IDF 的计算方式是,首先统计所有文档中包含该词的文档数,再用总文档数除以包含该词的文档数,得到一个标量,再对其取对数得到 IDF。

具体来讲,IDF 的计算公式为:

IDF = log( (total_number_of_documents+1) / (number_of_documents_containing_term + 1) )

其中total_number_of_documents表示总文档数,number_of_documents_containing_term表示包含该词的文档数。

需要注意的是,IDF 值的计算是基于总文档数的,而不是查询中的文档数。IDF 值越大,表示该词的重要程度越高,因此文档中包含该词的相关得分就越高。

例如,假设我们有一个包含 10,000 篇文档的索引,其中包含 1,000 篇文档包含词语"elasticsearch",那么"elasticsearch"的 IDF 值就是:

IDF = log((10000+1)/(1000+1)) = 1.38629

 

以下是一个根据相关性得分排序的示例,假设我们的索引中有两篇文档,它们的内容如下:

[ { "title": "Elastic Stack入门指南", "content": "在本文中,我们将介绍如何使用Elastic Stack处理和分析日志数据。Elastic Stack是一组功能强大且易于使用的开源工具,被广泛应用于日志分析、安全分析、网络分析、指标分析等各种场景。" }, { "title": "如何使用Elasticsearch进行全文搜索", "content": "Elasticsearch是一个分布式的搜索引擎,它非常适合处理大量的结构化和非结构化数据,尤其是文本数据。在本文中,我们将介绍如何使用Elasticsearch进行全文搜索,包括构建索引、查询语法、相关性得分等方面的内容。" } ]

 

我们的目标是搜索所有包含“全文搜索”的文档,然后将它们根据相关性得分从高到低进行排序。我们可以使用以下查询:

GET my_index/_search { "query": { "multi_match": { "query": "全文搜索", "fields": ["title", "content"] } }, "sort": [ { "_score": { "order": "desc" } } ] }

 

在这个查询中,我们使用了multi_match查询,将查询关键字“全文搜索”在title字段和content字段中的匹配都纳入了考虑范围,它们将被视为在进行排序时一起考虑的两个独立的查询条件。使用相关性得分对搜索结果进行排序,文档将按照相关性得分从高到低进行排序,得分高的文档将排在前面。我们在查询中使用了_score字段进行排序,Elasticsearch将根据每个文档与查询之间的相关性得分来计算它们的排名。

 

假设第一篇文档的相关性得分为1.5,第二篇文档的相关性得分为1.0。那么最终排序后的结果将是:

[ { "title": "如何使用Elasticsearch进行全文搜索", "content": "Elasticsearch是一个分布式的搜索引擎,它非常适合处理大量的结构化和非结构化数据,尤其是文本数据。在本文中,我们将介绍如何使用Elasticsearch进行全文搜索,包括构建索引、查询语法、相关性得分等方面的内容。", "_score": 1.5 }, { "title": "Elastic Stack入门指南", "content": "在本文中,我们将介绍如何使用Elastic Stack处理和分析日志数据。Elastic Stack是一组功能强大且易于使用的开源工具,被广泛应用于日志分析、安全分析、网络分析、指标分析等各种场景。", "_score": 1.0 } ]

 

可以看到,我们得到了符合预期的结果,根据相关性得分将包含“全文搜索”的文档排序输出。

 

  • multi_match是Elasticsearch中一个可以同时对多个字段进行搜索的查询语句。它常用于针对同一关键字对多个字段进行搜索,并将多个字段的搜索结果合并起来。

multi_match查询可以使用各种类型的匹配询子句,比如matchmatch_phraseprefixwildcard等,在进行多个字段的查询时,还可以为每个字段指定不同的查询类型。在multi_match语句中,查询条件会被自动扩展到所有的索引字段中,不需要为每个字段单独写一个match子句。

以下是一个multi_match查询的示例,通过同时针对两个字段进行搜索:

GET my_index/_search { "query": { "multi_match": { "query": "elasticsearch 入门", "fields": ["title", "content"] } } }

 

在这个示例中,我们将查询关键字 "elasticsearch 入门" 在 "title" 和 "content" 两个字段中搜索。由于没有指定任何查询类型,Elasticsearch会自动为这两个字段选择一个合适的查询类型。

当我们想要在搜索结果中使用相关性得分对结果进行排序时,通常会使用以下类似的查询:

GET my_index/_search { "query": { "multi_match": { "query": "elasticsearch 入门", "fields": ["title", "content"] } }, "sort": [ { "_score": { "order": "desc" } } ] }

 

在这个查询中,我们将multi_match查询和sort排序语句组合起来,按照相关性得分从高到低进行排序(使用了_score字段),相关性得分高的文档将排在前面。

 

multi_match 查询可以理解为多个 match 查询组成的 should 语句。这意味着,如果文档至少满足其中一个 match 查询的条件,则可以匹配。举个例子,下面两个查询是等效的:

使用 multi_match

{
  "query": {
    "multi_match": {
      "query": "Shanghai China",
      "fields": ["title", "content"]
    }
  }
}

使用 should

{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title": "Shanghai China"
          }
        },
        {
          "match": {
            "content": "Shanghai China"
          }
        }
      ]
    }
  }
}

不过需要注意,multi_match 子句可以选择性地指定查询运算符,例如 and 或 or,这可以在处理不同的查询场景时提供更多的控制选项。

 

在 multi_match 查询中使用指定的查询运算符,例如 AND 或 OR,可以控制其多个查询子句的相对重要性,以及如何在查询中组合并排除符合条件的文档。例如:

{
  "query": {
    "multi_match": {
      "query": "电视",
      "fields": ["标题", "内容"],
      "type": "best_fields",
      "operator": "AND"
    }
  }
}

假设上面的查询语句是针对 商品 索引的,其中包含 标题 和 内容 两个字段。该查询意味着,“在所有文档中,返回所有包含 电视 的文档,并且该文档必须同时包含 标题 字段和 内容 字段中的 电视 关键字。

posted @ 2023-05-11 10:55  机械公敌  阅读(284)  评论(0编辑  收藏  举报