Elasticsearch 复合查询

153 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

复合查询

使用bool查询

接受以下参数:

  • must:文档必须匹配设定条件才能被包含进来
  • must_not:文档必须不匹配设定条件才能被包含进来
  • should:如果满足语句中的任意语句,将增加_source,否则,无任何影响。主要用于修正每个文档的相关性得分
  • filter:必须匹配,但以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档

相关性得分是如何组合的?

每一个子查询都独自的计算文档的相关性得分,bool查询将对计算出的等分进行合并,然后返回一个代表整个布尔操作的等分。

下面的查询用于查找title字段匹配 how to make millions 并且不被标识为 spam的文档。那些被标识为 starred 或在2014之后的文档,将比另外那些文档拥有更高的排名。如果 两者 都满足,那么它的排名将更高。

GET /lib3/user/_search
{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "interests": "changge"
                }
            },
            "must_not": {
                "match": {
                    "interests": "lvyou"
                }
            },
            "should": [
                {
                    "match": {
                        "address": "bei jing"
                    }
                },
                {
                    "range": {
                        "birthday": {
                            "gte": "1996-01-01"
                        }
                    }
                }
            ]
        }
    }
}

如果没有 must 语句,那么至少需要能够匹配其中的一条 should 语句。但如果存在至少一条 must 语句,则对 should 语句的匹配没有要求。如果不想因为文档的时间影响得分,可以用 filter 语句来重写前面的例子

# 可以在bool内嵌套filter过滤
GET /lib3/user/_search
{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "interests": "changge"
                }
            },
            "must_not": {
                "match": {
                    "interests": "lvyou"
                }
            },
            "should": [
                {
                    "match": {
                        "address": "bei jing"
                    }
                }
            ],
            "filter": {
                "range": {
                    "birthday": {
                        "gte": "1996-01-01"
                    }
                }
            }
        }
    }
}

通过将 range 查询移动到 filter 语句中,我们将它转成不评分的查询,将不在影响文档的相关性排名,由于它现在是一个不评分的查询,可以使用各种对 filter 查询有效的优化手段来提升性能。

bool 查询本身也可以被用作不评分的查询,简单的将它放置到 filter 语句中并在内部构建布尔逻辑

# 在bool内嵌套fliter,在fliter下嵌套另一个bool作为过滤条件
GET /lib3/user/_search
{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "interests": "changge"
                }
            },
            "must_not": {
                "match": {
                    "interests": "lvyou"
                }
            },
            "should": [
                {
                    "match": {
                        "address": "bei jing"
                    }
                }
            ],
            "filter": {
                "bool": {
                    "must": [
                        {
                            "range": {
                                "birthday": {
                                    "gte": "1990-01-01"
                                }
                            }
                        },
                        {
                            "range": {
                                "age": {
                                    "lte": 30
                                }
                            }
                        }
                    ],
                    "must_not": [
                        {
                            "term": {
                                "age": "29"
                            }
                        }
                    ]
                }
            }
        }
    }
}

constant_score查询

constant_score将一个不变的量评分应用于所有匹配的文档,被经常用于你只需要执行一个 fliter 而没有其他查询(例如:评分查询)的情况下。 请求结构如下:

{
	"constant_score": {
		"filter": {
			"term": {
				"category": "ebooks"
			}
		}
	}
}

示例:

GET /lib4/items/_search
{
    "query": {
        "constant_score": {
            "filter": {
                "term": {
                    "interests": "changge"
                }
            }
        }
    }
}

term 查询被放置在constant_score中,转成不评分的 filter。这种方式可以用来取代只有 filter 语句的 bool 查询。