elasticsearch之十五springboot测试文档复合

2020-04-01  本文已影响0人  Java及SpringBoot

个人专题目录](https://www.jianshu.com/p/140e2a59db2c)


elasticsearch文档复合查询及排序

1. 复合查询

1.1 bool查询

bool (布尔)过滤器。 这是个复合过滤器(compound filter) ,它可以接受多个其他过滤器作为参数,并将这些过滤器结合成各式各样的布尔(逻辑)组合。
格式
一个 bool 过滤器由三部分组成:

{
   "bool" : {
      "must" :     [],
      "should" :   [],
      "must_not" : [],
   }
}

参数定义:

must
所有的语句都 必须(must) 匹配,与 AND 等价。
must_not
所有的语句都不能(must not) 匹配,与 NOT 等价。
should
至少有一个语句要匹配,与 OR 等价。

例如查询条件:

POST /book-index/_search
{
  "from": 0,
  "size": 100,
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": {
              "query": "三星",
              "operator": "OR",
              "prefix_length": 0,
              "max_expansions": 50,
              "fuzzy_transpositions": true,
              "lenient": false,
              "zero_terms_query": "NONE",
              "auto_generate_synonyms_phrase_query": true,
              "boost": 1
            }
          }
        }
      ],
      "must_not": [
        {
          "term": {
            "brandName": {
              "value": "诺基亚",
              "boost": 1
            }
          }
        }
      ],
      "should": [
        {
          "term": {
            "categoryName": {
              "value": "手机",
              "boost": 1
            }
          }
        },
        {
          "term": {
            "categoryName": {
              "value": "平板电视",
              "boost": 1
            }
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  }
}
@Override
public void boolQuery(String indexName) throws Exception {
    BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
    queryBuilder.should(QueryBuilders.termQuery("categoryName", "手机"));
    queryBuilder.should(QueryBuilders.termQuery("categoryName", "平板电视"));
    queryBuilder.must(QueryBuilders.matchQuery("title", "三星"));
    queryBuilder.mustNot(QueryBuilders.termQuery("brandName", "诺基亚"));
    builder(indexName, queryBuilder);
}
@Test
public void testBoolQuery() throws Exception {
    baseQuery.boolQuery(Constants.INDEX_NAME);
}

1.2 booting查询

该查询用于将两个查询封装在一起,并降低其中一个查询所返回文档的分值。

它接受一个positive查询和一个negative查询。只有匹配了positive查询的文档才会被包含到结果集中,但是同时匹配了negative查询的文档会被降低其相关度,通过将文档原本的_score和negative_boost参数进行相乘来得到新的_score。因此,negative_boost参数必须小于1.0。在上面的例子中,任何包含了指定负面词条的文档的_score都会是其原本_score的一半。

例如:

在互联网上搜索"苹果"也许会返回,水果或者各种食谱的结果。我们可以通过排除“水果 乔木 维生素”和这类单词,结合bool查询中的must_not子句,将结果范围缩小到只剩苹果手机。

POST  /book-index/_search
{
    "query": {
        "boosting": {
            "positive": {
                "match": {
                    "title": {
                        "query": "三星 手机 联通",
                        "operator": "AND",
                        "prefix_length": 0,
                        "max_expansions": 50,
                        "fuzzy_transpositions": true,
                        "lenient": false,
                        "zero_terms_query": "NONE",
                        "auto_generate_synonyms_phrase_query": true,
                        "boost": 1.0
                    }
                }
            },
            "negative": {
                "match": {
                    "title": {
                        "query": "白色 黑色",
                        "operator": "OR",
                        "prefix_length": 0,
                        "max_expansions": 50,
                        "fuzzy_transpositions": true,
                        "lenient": false,
                        "zero_terms_query": "NONE",
                        "auto_generate_synonyms_phrase_query": true,
                        "boost": 1.0
                    }
                }
            },
            "negative_boost": 0.1,
            "boost": 1.0
        }
    }
}
@Override
public void boostingQuery(String indexName, String positiveField, String positiveKeyWord, String negativeField, String negativeKeyWord) throws Exception {
    MatchQueryBuilder matchQueryPositiveBuilder = QueryBuilders.matchQuery(positiveField, positiveKeyWord);
    MatchQueryBuilder matchQueryNegativeBuilder = QueryBuilders.matchQuery(negativeField, negativeKeyWord);
    BoostingQueryBuilder boostingQueryBuilder = QueryBuilders.boostingQuery(matchQueryPositiveBuilder,
            matchQueryNegativeBuilder).negativeBoost(0.1f);

    builder(indexName, boostingQueryBuilder);
}
/**
 * 它接受一个positive查询和一个negative查询。只有匹配了positive查询的文档才会被包含到结果集中,
 * 但是同时匹配了negative查询的文档会被降低其相关度,通过将文档原本的_score和negative_boost参数进行相乘来得到新的_score。
 * 因此,negative_boost参数必须小于1.0。在上面的例子中,任何包含了指定负面词条的文档的_score都会是其原本_score的一半。
 *
 * @throws Exception
 */
@Test
public void testBoostingQuery() throws Exception {
    //都可以查出来,只是SCORE值减少,可以通过SCORE值来去掉排名在后面的
    baseQuery.boostingQuery(Constants.INDEX_NAME, "title", "三星 手机 联通", "title", "白色 黑色");
}

2. 排序(Sort)

默认情况下,结果集会按照相关性进行排序 -- 相关性越高,排名越靠前。

为了使结果可以按照相关性进行排序,我们需要一个相关性的值。在ElasticSearch的查询结果中, 相关性分值会用_score字段来给出一个浮点型的数值,所以默认情况下,结果集以_score进行倒序排列。

注意:在Elasticsearch中,如果使用text类型的字段作为排序依据,会有问题。Elasticsearch需要对text类型字段数据做分词处理。如果使用text类型字段做排序,Elasticsearch给出的排序结果未必友好,毕竟分词后,先使用哪一个单词做排序都是不合理的。所以Elasticsearch中默认情况下不允许使用text类型的字段做排序,如果需要使用字符串做结果排序,则可使用keyword类型字段作为排序依据,因为keyword字段不做分词处理。

如果对一个text field进行排序,结果往往不准确,因为分词后是多个单词,再排序就不是我们想要的结果了。

通常解决方案是,将一个text field建立两次索引,一个分词,用来进行搜索;一个不分词,用来进行排序。

fielddate:true

{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "title.keyword": {
        "order": "desc"
      }
    }
  ]
}
POST /book-index/_search
{
  "query": {
    "match": {
      "brandName": {
        "query": "三星",
        "operator": "OR",
        "prefix_length": 0,
        "max_expansions": 50,
        "fuzzy_transpositions": true,
        "lenient": false,
        "zero_terms_query": "NONE",
        "auto_generate_synonyms_phrase_query": true,
        "boost": 1
      }
    }
  },
  "sort": [
    {
      "id": {
        "order": "desc"
      }
    }
  ]
}
@Override
public void sortQuery(String indexName, String field, String keyWord, String sort, SortOrder sortOrder) throws IOException {
    SearchRequest searchRequest = new SearchRequest(indexName);
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.matchQuery(field, keyWord));
    searchSourceBuilder.sort(sort, sortOrder);
    searchRequest.source(searchSourceBuilder);
    log.info("source:" + searchRequest.source());
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    SearchHits hits = searchResponse.getHits();
    log.info("count:" + hits.getTotalHits());
    SearchHit[] h = hits.getHits();
    for (SearchHit hit : h) {
        log.info("结果" + hit.getSourceAsMap() + ",score:" + hit.getScore());
    }
}
@Test
public void testSortQueryBySort() throws IOException {
    sortQuery.sortQuery(Constants.INDEX_NAME, "brandName", "三星", "id", SortOrder.DESC);
}
上一篇下一篇

猜你喜欢

热点阅读