elasticsearch-net
elasticsearch-net copied to clipboard
Unable to use descriptors to set Fields in MultiMatchQueryDescriptor query
Is your feature request related to a problem? Please describe. When trying to migrate our Nest code to the new client I ran into a problem migrating a Multimatch query. In Nest, we could use descriptors to set with fields the multimatch should use for the query. This is not available in the new client, forcing me to use magic strings.
Here is the MultiMatch portion of the query using the new client, with the Nest code commented out.
.MultiMatch(mm => mm
.Type(TextQueryType.BestFields)
.Fields(new[]
{
"name.lownerngram",
"tags.lowerekeyword"
})
//.Fields(fds => fds
// .Field(f => f.Name.Suffix("lowerngram"))
// .Field(f => f.Tags.Suffix("lowerkeyword"))
//)
.Query(queryString)
)
Describe the solution you'd like Would like to use descriptors to set the fields the multimatch query will use in a way similar to the commented out code.
Hi @ashitanojoe ,
This is one of the features I definitely plan to bring back. I sadly can't give you an ETA.
As a workaround, the Field
type can be constructed like this:
Field<TDocument>(f => f.Name)
which allows for:
.MultiMatch(mm => mm
.Type(TextQueryType.BestFields)
.Fields(new[]
{
Field<TDocument>(f => f.Name),
Field<TDocument>(f => f.Tags)
})
.Query(queryString)
)
I'm not sure, if .Suffix()
is implemented already, but you could create your own extension method for the Field
class in order to support this functionality, if it's not yet implemented.
Hi @flobernd ,
Thank you for pointing out the workaround. Not sure how I missed that. I definitely like that better than passing a string.
I found this issue when trying to migrate some QueryString queries in 8.15.x and I was struggling to find any examples that didn't use magic strings for Fields. I'm sorry if I'm being obtuse but I can't find any generic constructor in the style of Field<TDocument>(f => f.Name)
so is this workaround no longer correct?
I couldn't get the suggested workaround to work either, so I ended up using magic strings.
Hi @braveyp @ashitanojoe,
I'm very sorry about the wrong syntax example I've provided. The correct syntax is as follows:
var response = await client.SearchAsync<Person>(r => r
.Index("person")
.Query(q => q
.QueryString(qs => qs
.Fields(new Expression<Func<Person, object>>[]
{
f => f.Age!,
f => f.FirstName!
})
)
)
);
The Fields
type has an implicit conversion operator from Expression[]
:
public static implicit operator Fields?(Expression[]? expressions)
To make use of this, it's required to explicitly declare the type of the array parameter (new Expression<Func<Person, object>>[]
) like shown above.
The NEST syntax from the initial post is not going to be re-introduced:
.Fields(fds => fds
.Field(f => f.Name.Suffix("lowerngram"))
.Field(f => f.Tags.Suffix("lowerkeyword"))
)
But, my plan is to change the code generator in a way that it generates this overload:
public QueryStringQueryDescriptor<TDocument> Fields(params Expression<Func<TDocument, object>> fields)
in addition to the current:
public QueryStringQueryDescriptor<TDocument> Fields(Elastic.Clients.Elasticsearch.Fields? fields)
This will then allow to pass an array of Expression
without explicitly having to define the expression type:
var response = await client.SearchAsync<Person>(r => r
.Index("person")
.Query(q => q
.QueryString(qs => qs
.Fields(
f => f.Age!,
f => f.FirstName!
)
)
)
);
Thanks for the help, that works perfectly.