将 FunctionScore/FieldValueFactor 添加到 MultiMatch 查询

Adding FunctionScore/FieldValueFactor to a MultiMatch query

我们有一个非常基本的查询,我们正在使用它来允许用户提供查询文本,然后它会提高不同字段的匹​​配度。现在我们想添加另一个 boost based on votes,但不确定将 FunctionScore 嵌套在何处。

我们原来的查询是:

var results = await _ElasticClient.SearchAsync<dynamic>(s => s
    .Query(q => q
        .MultiMatch(mm => mm
            .Fields(f => f
                .Field("name^5")
                .Field("hobbies^2")
            )
            .Query(queryText)
        )
    )
);

如果我尝试在 FunctionScore 中嵌套在 MultiMatch 周围,它基本上会忽略 query/fields,而只是 returns 索引中的所有内容:

var results = await _ElasticClient.SearchAsync<dynamic>(s => s
    .Query(q => q
        .FunctionScore(fs => fs
            .Query(q2 => q2
                .MultiMatch(mm => mm
                    .Fields(f => f
                        .Field("name^5")
                        .Field("hobbies^2")
                    )
                    .Query(queryText)
                )
            )
        )
    )
);

我的期望是,由于我没有提供 FunctionScore 或任何 Functions,这基本上应该与上面的完全相同。然后,只需添加 FunctionScore 即可根据我提供的功能对结果进行提升(在我的例子中,基于 votes 字段的提升只是 FieldValueFactor)。

关于此的文档有点模糊,尤其是某些组合,如 MultiMatchFunctionScore 和查询文本。我确实找到了 this answer,但在包含查询文本时它没有涵盖。

我很确定这归结为我对 Elastic 查询如何工作的理解仍然模糊不清,但我只是没有找到太多内容来涵盖(我认为很常见的)场景:

您的 function_score 查询是正确的,但您没有看到预期结果的原因是 NEST 中的一项功能称为 conditionless queries。在 function_score 查询的情况下,当没有函数时,它被认为是无条件的,从请求中发送的序列化表单中省略查询。

最简单的方法是看一个小例子

private static void Main()
{
    var defaultIndex = "my-index";
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

    var settings = new ConnectionSettings(pool, new InMemoryConnection())
        .DefaultIndex(defaultIndex)
        .DisableDirectStreaming()
        .PrettyJson()
        .OnRequestCompleted(callDetails =>
        {
            if (callDetails.RequestBodyInBytes != null)
            {
                Console.WriteLine(
                    $"{callDetails.HttpMethod} {callDetails.Uri} \n" +
                    $"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
            }
            else
            {
                Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
            }

            Console.WriteLine();

            if (callDetails.ResponseBodyInBytes != null)
            {
                Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                         $"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
                         $"{new string('-', 30)}\n");
            }
            else
            {
                Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                         $"{new string('-', 30)}\n");
            }
        });

    var client = new ElasticClient(settings);

    var queryText = "query text";

    var results = client.Search<dynamic>(s => s
        .Query(q => q
            .FunctionScore(fs => fs
                .Query(q2 => q2
                    .MultiMatch(mm => mm
                        .Fields(f => f
                            .Field("name^5")
                            .Field("hobbies^2")
                        )
                        .Query(queryText)
                    )
                )
            )
        )
    );
}

发出以下请求

POST http://localhost:9200/my-index/object/_search?pretty=true&typed_keys=true 
{}

您可以通过将查询标记为 Verbatim

来禁用 conditionless 功能
var results = client.Search<dynamic>(s => s
    .Query(q => q
        .FunctionScore(fs => fs
            .Verbatim() // <-- send the query *exactly as is*
            .Query(q2 => q2
                .MultiMatch(mm => mm
                    .Fields(f => f
                        .Field("name^5")
                        .Field("hobbies^2")
                    )
                    .Query(queryText)
                )
            )
        )
    )
);

现在发送查询

POST http://localhost:9200/my-index/object/_search?pretty=true&typed_keys=true 
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {
          "query": "query text",
          "fields": [
            "name^5",
            "hobbies^2"
          ]
        }
      }
    }
  }
}