布尔匹配

到现在为止,你可能已经意识到在一个布尔查询中多字段match查询仅仅包裹了已经生成的term查询。通过默认的or操作符,每个term查询都会像一个should子句一样被添加,只要有一个子句匹配就可以了。

下面的两个查询是等价的:

  • {
        "match": { "title": "brown fox"}
    }
    
  • {
      "bool": {
        "should": [
          { "term": { "title": "brown" }},
          { "term": { "title": "fox"   }}
        ]
      }
    }
    

通过and操作符,所有的term查询会像must子句一样被添加,因此所有的子句都必须匹配。下面的两个查询是等价的:

  • {
        "match": {
            "title": {
                "query":    "brown fox",
                "operator": "and"
            }
        }
    }
    
  • {
      "bool": {
        "must": [
          { "term": { "title": "brown" }},
          { "term": { "title": "fox"   }}
        ]
      }
    }
    

如果minimum_should_match参数被指定,match查询就直接被转换成一个bool查询,下面两个查询是等价的:

  • {
        "match": {
            "title": {
                "query":                "quick brown fox",
                "minimum_should_match": "75%"
            }
        }
    }
    
  • {
      "bool": {
        "should": [
          { "term": { "title": "brown" }},
          { "term": { "title": "fox"   }},
          { "term": { "title": "quick" }}
        ],
        "minimum_should_match": 2 <1>
      }
    }
    

因为只有三个子句,所以 minimum_should_match参数在match查询中的值75%就下舍到了2。3个should子句中至少有两个子句匹配。

当然,我们通常写这些查询类型的时候还是使用match查询的,但是理解match查询在内部是怎么工作的可以让你在任何你需要使用的时候更加得心应手。有些情况仅仅使用一个match查询是不够的,比如给某些查询词更高的权重。这种情况我们会在下一节看个例子。

当然,bool查询并不仅仅是组合多个简单的一个词的match查询。他可以组合任何其他查询,包括bool查询。bool查询通常会通过组合几个不同查询的得分为每个文档调整相关性得分。

假设我们想查找关于"full-text search"的文档,但是我们又想给涉及到“Elasticsearch”或者“Lucene”的文档更高的权重。我们的用意是想涉及到"Elasticsearch" 或者 "Lucene"的文档的相关性得分会比那些没有涉及到的文档的得分要高,也就是说这些文档会出现在结果集更靠前的位置。

一个简单的bool查询允许我们写出像下面一样的非常复杂的逻辑:

GET /_search
{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "content": { (1)
                        "query":    "full text search",
                        "operator": "and"
                    }
                }
            },
            "should": [ (2)
                { "match": { "content": "Elasticsearch" }},
                { "match": { "content": "Lucene"        }}
            ]
        }
    }
}
  1. content字段必须包含full,text,search这三个单词。
  2. 如果content字段也包含了“Elasticsearch”或者“Lucene”,则文档会有一个更高的得分。

匹配的should子句越多,文档的相关性就越强。到目前为止一切都很好。但是如果我们想给包含“Lucene”一词的文档比较高的得分,甚至给包含“Elasticsearch”一词更高的得分要怎么做呢?

我们可以在任何查询子句中指定一个boost值来控制相对权重,默认值为1。一个大于1的boost值可以提高查询子句的相对权重。因此我们可以像下面一样重写之前的查询:

GET /_search
{
    "query": {
        "bool": {
            "must": {
                "match": {  (1)
                    "content": {
                        "query":    "full text search",
                        "operator": "and"
                    }
                }
            },
            "should": [
                { "match": {
                    "content": {
                        "query": "Elasticsearch",
                        "boost": 3 (2)
                    }
                }},
                { "match": {
                    "content": {
                        "query": "Lucene",
                        "boost": 2 (3)
                    }
                }}
            ]
        }
    }
}
  1. 这些查询子句的boost值为默认值1
  2. 这个子句是最重要的,因为他有最高的boost值。
  3. 这个子句比第一个查询子句的要重要,但是没有“Elasticsearch”子句重要。

注意:

  1. boost参数用于提高子句的相对权重(boost值大于1)或者降低子句的相对权重(boost值在0-1之间),但是提高和降低并非是线性的。换句话说,boost值为2并不能够使结果变成两部的得分。
  2. 另外,boost值被使用了以后新的得分是标准的。每个查询类型都会有一个独有的标准算法,算法的详细内容并不在本书的范畴。简单的概括一下,一个更大的boost值可以得到一个更高的得分。
  3. 如果你自己实现了没有基于TF/IDF的得分模型,但是你想得到更多的对于提高得分过程的控制,你可以使用function_score查询来调整一个文档的boost值而不用通过标准的步骤。
下一节:查询只能查找在倒排索引中出现的词,所以确保在文档索引的时候以及字符串查询的时候使用同一个分析器是很重要的,为了查询的词能够在倒排索引中匹配到。

尽管我们说文档中每个字段的分析器是已经定好的。但是字段可以有不同的分析器,通过给那个字段配置一个指定的分析器或者直接使用类型,索引,或节点上的默认分析器。在索引的时候,一个字段的值会被配置的或者默认的分析器分析。