Elasticsearch请求优化(Java API中带有bool查询的奇怪script_score)

时间:2015-10-08 13:12:43

标签: java elasticsearch

使用Elasticsearch 1.7.0,我想对文档的文本字段进行查询。我需要获得所有文件:

  1. 部分匹配(所有单词都需要与同义词和模糊一起存在)

  2. 匹配模糊(所有单词需要存在+模糊+拼音)

  3. 匹配相关(需要找到50%的单词)

  4. 我制作了一个包含3个Elasticsearch请求的Java程序,但这些查询太长了,所以我尝试使用一个查询:

    {
      "query": 
        {"bool": {
          "should": [
            {
                  "function_score": {
                  "boost_mode": "replace",
                  "query": {
                    "match": {
                      "text.syn": {
                        "query": "sorbone",
                        "operator": "and",
                        "fuzziness": 1,
                        "minimum_should_match": "100%"
                      }
                    }
                  },
                  "script_score": {
                    "script": "1"
                  }
              }
            },
            {
                  "function_score": {
                  "boost_mode": "replace",
                  "query": {
                    "match": {
                      "text.phonetic": {
                        "query": "sorbone",
                        "operator": "and",
                        "fuzziness": 1,
                        "minimum_should_match": "100%"
                      }
                    }
                  },
                  "script_score": {
                    "script": "3"
                  }
              }
            },
            {
                  "function_score": {
                  "boost_mode": "replace",
                  "query": {
                    "match": {
                      "text.phonetic": {
                        "query": "sorbone",
                        "operator": "or",                    
                        "minimum_should_match": "50%"
                      }
                    }
                  },
                  "script_score": {
                    "script": "7"
                  }
              }
            }
          ]
        }
      }
    }
    

    我们的想法是为返回的每个文档使用一个特定分数的bool_query。它工作得很好但是当我尝试使用Java API转换它时,我得到一个奇怪的计算得分,而不是得分中有小数,我等着7 3 1 4 10 8这样的数字对应于得分总和。 / p>

    我使用的代码:

                .operator(org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND)
                .fuzziness(Fuzziness.ONE)
                .minimumShouldMatch("100%");
        QueryBuilder termsPhon = matchQuery("text.phonetic", "sorbonne")
                .operator(org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND)
                .fuzziness(Fuzziness.ONE)
                .minimumShouldMatch("100%");
        QueryBuilder termsText = matchQuery("text", "sorbonne")
                .operator(org.elasticsearch.index.query.MatchQueryBuilder.Operator.OR)
                .minimumShouldMatch("50%");
        QueryBuilder functionScorePartial = functionScoreQuery(termsSyn)
                .add(ScoreFunctionBuilders.scriptFunction("1"))
                .boostMode("replace");    
    
    
    QueryBuilder functionScoreFuzzy = functionScoreQuery(termsPhon)
            .add(ScoreFunctionBuilders.scriptFunction("7"))
            .boostMode("replace");    
    
    QueryBuilder functionScoreRelated = functionScoreQuery(termsText)
            .add(ScoreFunctionBuilders.scriptFunction("15"))
            .boostMode("replace")
            ;    
    
    QueryBuilder boolQ = boolQuery()
            .should(functionScorePartial)
            .should(functionScoreFuzzy)
            .should(functionScoreRelated);
    
    sqb.setQuery(boolQ);
    
    
    SearchResponse response = sqb.execute().actionGet();
    SearchHits hits = response.getHits();
    

    当我查看生成的JSON时,我发现脚本函数的生成方式不同。在最初的REST中我得到了:

    "functions" : [ {
          "script_score" : {
            "script" : "1"
          }
        } ],
        "boost_mode" : "replace"
    

    在生成的JSON中,没有“函数”数组:

     "script_score": {
                "script": "1"
     }
    

    这是Elasticsearch Java API中的错误吗?

2 个答案:

答案 0 :(得分:0)

match查询为每个匹配的查询返回基于Lucene scoring formula (TF-IDF ish)的小数分数 - 然后乘以您在查询中提供的提升。

  

当查询包含时,这实际上对您有利   多个匹配术语(或多个扩展术语匹配时)。

对于您正在实施的更简单的评分策略,您需要使用Constant Score Queries 将过滤器包装在您的bool查询中。这将允许您为每个匹配条件返回常量分数

更新:即使使用常量得分查询,由于查询规范化,OP也未在bool查询中看到预期得分。 function_score查询的原始想法是在正确的轨道上(用于实现完全自定义评分),但也通过外部bool查询遭受查询规范化。

避免这种规范化的方法是使function_score查询成为最外层的查询(并使三个匹配条件成为您的评分函数):

{
  "query": {
    "function_score": {
      "score_mode": "sum",
      "boost_mode": "replace",
      "filter": {
        "bool": {
          "should": [{
            "query": {
              "match": {
                "text.syn": {
                  "query": "sorbone",
                  "operator": "and",
                  "fuzziness": 1,
                  "minimum_should_match": "100%"
                }
              }
            }
          }, {
            "query": {
              "match": {
                "text.phonetic": {
                  "query": "sorbone",
                  "operator": "or",
                  "minimum_should_match": "50%"
                }
              }
            }
          }]
        }
      },
      "functions": [{
        "filter": {
          "query": {
            "match": {
              "text.syn": {
                "query": "sorbone",
                "operator": "and",
                "fuzziness": 1,
                "minimum_should_match": "100%"
              }
            }
          }
        },
        "weight": 1
      }, {
        "filter": {
          "query": {
            "match": {
              "text.phonetic": {
                "query": "sorbone",
                "operator": "and",
                "fuzziness": 1,
                "minimum_should_match": "100%"
              }
            }
          }
        },
        "weight": 3
      }, {
        "filter": {
          "query": {
            "match": {
              "text.phonetic": {
                "query": "sorbone",
                "operator": "or",
                "minimum_should_match": "50%"
              }
            }
          }
        },
        "weight": 7
      }]
    }
  }
}

请注意,3个匹配条件中的2个也用作filter查询的初始function_score子句,因此无需对整个集合进行评分。 (一个标准被省略为过滤冗余 - 因为100%的语音术语匹配是50%语音术语匹配的子集)

答案 1 :(得分:0)

使用此代码并使用constantScoreQuery再次为我提供浮点数:(

  

QueryBuilder boolQ = boolQuery()      。应该(constantScoreQuery(termsSyn).boost(1))
     。应该(constantScoreQuery(termsPhon).boost(7))      。应该(constantScoreQuery(termsText).boost(15));
     sqb.setQuery(boolQ);