I am trying to query using NEST and the multimatch option, but the results are not coming out as expected.
I submit a term that should be compared to several fields. However, if you do not set a search term, all documents must be returned.
I saw that it was possible to use a keyword like "*. *" But it did not work. Any suggestion?
var searchResponse = client.Search<DocumentElasticModel>(s => s
.Size(pageSize)
.Skip(currentPageIndex * pageSize)
.Sort(ss => ss
.Descending(SortSpecialField.Score)
)
.Source(sf => sf
.Includes(i => i
.Fields(
returnedFields
)
)
)
.Query(q => q
.Nested(c => c
.Name("named_query")
.Boost(1.1)
.InnerHits(i => i.Explain())
.Path(p => p.PerguntasRespostas)
.Query(nq => nq
.MultiMatch(m => m
.Fields(f => filterFields)
-----------------------WHEN THE 'SEARCH' IS EMPTY, SHOULD FIND ALL -----------------
.Query(string.IsNullOrEmpty(search) ? string.Empty : search)
)
)
.IgnoreUnmapped()
)
)
NEST supports this by default with a concept referred to as Conditionless queries. You can
private static void Main()
{
var defaultIndex = "documents";
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 pageSize = 20;
var currentPageIndex = 0;
string search = "foo";
var searchResponse = client.Search<DocumentElasticModel>(s => s
.Size(pageSize)
.Skip(currentPageIndex * pageSize)
.Sort(ss => ss
.Descending(SortSpecialField.Score)
)
.Source(sf => sf
.Includes(i => i
.Fields(f => f.TopLevelMessage)
)
)
.Query(q => q
.Nested(c => c
.Name("named_query")
.Boost(1.1)
.InnerHits(i => i.Explain())
.Path(p => p.PerguntasRespostas)
.Query(nq => nq
.MultiMatch(m => m
.Fields(f => f
.Field(ff => ff.PerguntasRespostas.First().Message)
)
.Query(search)
)
)
.IgnoreUnmapped()
)
)
);
}
public class DocumentElasticModel
{
public string TopLevelMessage { get; set; }
public IEnumerable<PerguntasRespostas> PerguntasRespostas {get;set;}
}
public class PerguntasRespostas
{
public string Message { get; set; }
}
This would send the following query
POST http://localhost:9200/documents/documentelasticmodel/_search
{
"from": 0,
"size": 20,
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"_source": {
"includes": [
"topLevelMessage"
]
},
"query": {
"nested": {
"_name": "named_query",
"boost": 1.1,
"query": {
"multi_match": {
"query": "foo",
"fields": [
"perguntasRespostas.message"
]
}
},
"path": "perguntasRespostas",
"inner_hits": {
"explain": true
},
"ignore_unmapped": true
}
}
}
Now, if you change search
to string.Empty
or null
, you get
POST http://localhost:9200/documents/documentelasticmodel/_search
{
"from": 0,
"size": 20,
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"_source": {
"includes": [
"topLevelMessage"
]
}
}
With no explicit "query"
in the request, this is the same as a match_all
query.
If you wanted to override the conditionless query feature in NEST, you can mark the query as .Verbatim()
and NEST will send exactly as is
var searchResponse = client.Search<DocumentElasticModel>(s => s
.Size(pageSize)
.Skip(currentPageIndex * pageSize)
.Sort(ss => ss
.Descending(SortSpecialField.Score)
)
.Source(sf => sf
.Includes(i => i
.Fields(f => f.TopLevelMessage)
)
)
.Query(q => q
.Nested(c => c
.Verbatim() // <-- mark the nested query
.Name("named_query")
.Boost(1.1)
.InnerHits(i => i.Explain())
.Path(p => p.PerguntasRespostas)
.Query(nq => nq
.MultiMatch(m => m
.Verbatim() // <-- mark the inner query
.Fields(f => f
.Field(ff => ff.PerguntasRespostas.First().Message)
)
.Query(search)
)
)
.IgnoreUnmapped()
)
)
);
which sends
POST http://localhost:9200/documents/documentelasticmodel/_search
{
"from": 0,
"size": 20,
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"_source": {
"includes": [
"topLevelMessage"
]
},
"query": {
"nested": {
"_name": "named_query",
"boost": 1.1,
"query": {
"multi_match": {
"fields": [
"perguntasRespostas.message"
]
}
},
"path": "perguntasRespostas",
"inner_hits": {
"explain": true
},
"ignore_unmapped": true
}
}
}
You'll need to check if this is a valid query that Elasticsearch accepts.