将 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
)。
关于此的文档有点模糊,尤其是某些组合,如 MultiMatch
、FunctionScore
和查询文本。我确实找到了 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"
]
}
}
}
}
}
我们有一个非常基本的查询,我们正在使用它来允许用户提供查询文本,然后它会提高不同字段的匹配度。现在我们想添加另一个 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
)。
关于此的文档有点模糊,尤其是某些组合,如 MultiMatch
、FunctionScore
和查询文本。我确实找到了 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
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"
]
}
}
}
}
}