欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Elasticsearch实战——高级查询

程序员文章站 2022-03-05 10:00:26
...

Elasticsearch实战——高级查询

1. 复合查询

复合查询就是把一些简单查询组合在一起实现更复杂的查询需求,除此之外复合查询还可以控制另外一个查询的行为。

1.1 constant_score

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);

1.2 bool query

bool查询可以把任意多个简单的查询组合在一起,使用mustshouldmust_notfilter选项表示简单查询之间的逻辑,每个选项都可以出现0次到多次,它们的含义如下:

  • must:文档必须匹配must选项下的查询条件,相挡于逻辑运算符 AND
  • should:文档可以匹配should选项下的查询条件也可以不匹配,相挡于逻辑运算的OR
  • must_not:与must相反,匹配该选项下的查询条件的文档不会被返回
  • filter:和must一样,匹配filter选项下的查询条件的文档才会被返回,但是filter不评分,只起到过滤功能。

示例如下:

{
    "query":{
    	"bool":{
    		"must":[
    			{
    				"match":{
    					"title":"共享单车"
    				}
    			},
    			{
    				"term":{
    					"district":"昌平区"
    				}
    			}
    		],
    		"should":[
    			{
    				"match":{
    					"address":"朝阳区"
    				}
    			}	
    		]
    	}
    }
}

1.3 dis_max query

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":"北京朝阳区"
					}
				}
			]
    	}
    }
}

1.4 function_score query

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);

1.5 boosting query

boosting查询用于需要对两个查询的评分进行调整的场景,boosting查询会把两个查询封装在一起并降低其中一个查询的评分。

boosting查询包括positive,negativenegative_boost三部分,positive中的查询评分保持不变,negative中的查询会降低文档评分,negative_boost指明negative中降低的权值。

查询titlejava的书籍,出版时间在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);

2. 嵌套查询

2.1 父子查询

这里以店铺和商品为例,它们属于不同的的类型,相当于数据库中的两张表,如果想把店铺和它们经营的商品关联起来就需要告诉ES文档之间的父子关系,这里指定一个字段store2product来维护这种关系,该字段的类型为join,并指定它们的关系。

2.1.1 创建父子关系索引

PUT store
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "store2product": {
        "type": "join",
        "relations": {
          "storeid": "productid"
        }
      }
    }
  }
}

2.2.2 添加关系文档

添加父文档(店铺),并指定父字段

PUT store/1
{
  "name":"创实食品专营店",
  "store2product":"storeid"
}

添加子文档(商品),并且需要子文档和父文档在同一个分片,所以需要指定路由id父id

PUT store/2?routing=1
{
  "name":"创实 原味酸梅汤 速溶酸梅粉 冲饮果汁饮料1000g 酸梅汤原料",
  "store2product":{
    "name":"productid",
    "parent":"1"
  }
}

2.2.3 查询店铺下的商品

使用has_parent查询,并指定parent_typestoreid

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); 

2.2.4 查询商品属于哪个店铺

使用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);
相关标签: 搜索引擎