复合查询就是把一些简单查询组合在一起实现更复杂的查询需求,除此之外复合查询还可以控制另外一个查询的行为。
constant_score
query可以包装一个其他类型的查询,并返回匹配过滤器中的查询条件其具有相同评分的文档。当我们不关心检索词频率对搜索结果排序的影响时,可以使用constant_score
将查询语句query
或者过滤语句filter
包装起来。
示例如下:
{
"query":{
"constant_score":{
"filter":{
"term":{
"city":"北京市"
}
}
}
}
}
java示例如下:
MatchQueryBuilder query = QueryBuilders.matchQuery("title", "新闻").minimumShouldMatch("90%");
QueryBuilders.constantScoreQuery(query).boost(3.0f);
bool
查询可以把任意多个简单的查询组合在一起,使用must
、should
、must_not
、filter
选项表示简单查询之间的逻辑,每个选项都可以出现0次到多次,它们的含义如下:
must
:文档必须匹配must
选项下的查询条件,相挡于逻辑运算符 AND
。should
:文档可以匹配should
选项下的查询条件也可以不匹配,相挡于逻辑运算的OR
。must_not
:与must
相反,匹配该选项下的查询条件的文档不会被返回。filter
:和must
一样,匹配filter
选项下的查询条件的文档才会被返回,但是filter
不评分,只起到过滤功能。示例如下:
{
"query":{
"bool":{
"must":[
{
"match":{
"title":"共享单车"
}
},
{
"term":{
"district":"昌平区"
}
}
],
"should":[
{
"match":{
"address":"朝阳区"
}
}
]
}
}
}
dis_max query与bool query有一定联系也有一定区别,dis_max query支持多并发查询,可返回与任意查询条件子句匹配的文档类型。与bool查询可以将所有匹配查询的分数相结合的方式不同,dis_max查询只使用最佳查询条件的分数。
{
"query":{
"dis_max":{
"tie_breaker":0.7,
"boost":1.2,
"queries":[
{
"match":{"address":"北京朝阳区"}
},
{
"match":{
"title":"北京朝阳区"
}
}
]
}
}
}
function_score query可以修改查询的文档得分,这个查询在有些情况下非常有用,比如通过评分函数计算文档得分代价较高,可以改用过滤器加自定义评分函数的方式来取代传统的评分方式。
使用function_score query,用户需定义一个查询和一至多个评分函数,评分函数会对查询到的每个文档分别计算得分。
{
"query": {
"function_score": {
"query": {
"function_score": {
"query": {
"match": {
"title": "java编程"
}
},
"functions": [
{
"field_value_factor": {
"field": "price",
"factor": 0.1,
"modifier": "ln1p"
}
}
],
"score_mode": "multiply",
"max_boost": 10,
"boost": 1
}
},
"functions": [],
"score_mode": "multiply",
"boost_mode": "sum",
"max_boost": 10,
"boost": 1
}
}
}
java示例如下:
MatchPhraseQueryBuilder titleQuery = QueryBuilders.matchPhraseQuery("title", "java编程");
FieldValueFactorFunctionBuilder factor = ScoreFunctionBuilders.fieldValueFactorFunction("price").modifier(FieldValueFactorFunction.Modifier.LN1P).factor(0.1f);
FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = {
new FunctionScoreQueryBuilder.FilterFunctionBuilder(factor)
};
FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(titleQuery,filterFunctionBuilders);
FunctionScoreQueryBuilder query = QueryBuilders.functionScoreQuery(functionScoreQuery).boostMode(CombineFunction.SUM);
评分函数详解
boosting
查询用于需要对两个查询的评分进行调整的场景,boosting
查询会把两个查询封装在一起并降低其中一个查询的评分。
boosting
查询包括positive
,negative
和negative_boost
三部分,positive
中的查询评分保持不变,negative
中的查询会降低文档评分,negative_boost
指明negative
中降低的权值。
查询title
为java
的书籍,出版时间在2018年之前
的排在后面。
{
"query":{
"boosting":{
"positive":{
"match":{
"title":"java"
}
},
"negative":{
"range":{
"publishAt":{
"lte":"2018-01-01"
}
}
},
"negative_boost":0.2
}
}
}
java示例如下:
MatchPhraseQueryBuilder titleQuery = QueryBuilders.matchPhraseQuery("title", "java");
RangeQueryBuilder publishAt = QueryBuilders.rangeQuery("publishAt").lte("2018-01-01");
QueryBuilders.boostingQuery(titleQuery,publishAt).negativeBoost(0.2f);
这里以店铺和商品为例,它们属于不同的的类型,相当于数据库中的两张表,如果想把店铺和它们经营的商品关联起来就需要告诉ES文档之间的父子关系,这里指定一个字段store2product
来维护这种关系,该字段的类型为join,并指定它们的关系。
PUT store
{
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"store2product": {
"type": "join",
"relations": {
"storeid": "productid"
}
}
}
}
}
添加父文档(店铺),并指定父字段
PUT store/1
{
"name":"创实食品专营店",
"store2product":"storeid"
}
添加子文档(商品),并且需要子文档和父文档在同一个分片,所以需要指定路由id
为父id
PUT store/2?routing=1
{
"name":"创实 原味酸梅汤 速溶酸梅粉 冲饮果汁饮料1000g 酸梅汤原料",
"store2product":{
"name":"productid",
"parent":"1"
}
}
使用has_parent
查询,并指定parent_type
为storeid
GET store/_search
{
"query": {
"has_parent": {
"parent_type": "storeid",
"query": {
"match": {
"name": "食品专营店"
}
}
}
}
}
java示例如下:
MatchQueryBuilder nameQuery = QueryBuilders.matchQuery("name", "食品专营店");
HasParentQueryBuilder hasParentQueryBuilder = new HasParentQueryBuilder("storeid",nameQuery,true);
使用has_child
查询,并指定一个type
字段为productid
GET store/_search
{
"query": {
"has_child": {
"type":"productid",
"query": {
"match": {
"name": "原味酸梅汤"
}
}
}
}
}
java示例如下:
MatchQueryBuilder nameQuery = QueryBuilders.matchQuery("name", "原味酸梅汤");
HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder("productid",nameQuery, ScoreMode.None);
搜索微信公众号:java架构强者之路