Skip to content

Unable to use descriptors to set Fields in MultiMatchQueryDescriptor query #8013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Tracked by #8356
ashitanojoe opened this issue Jan 17, 2024 · 6 comments · Fixed by #8485
Closed
Tracked by #8356

Unable to use descriptors to set Fields in MultiMatchQueryDescriptor query #8013

ashitanojoe opened this issue Jan 17, 2024 · 6 comments · Fixed by #8485
Labels
8.x Relates to a 8.x client version Category: Feature Usability

Comments

@ashitanojoe
Copy link
Contributor

ashitanojoe commented Jan 17, 2024

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.

@flobernd flobernd added the 8.x Relates to a 8.x client version label Jan 17, 2024
@flobernd
Copy link
Member

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.

@ashitanojoe
Copy link
Contributor Author

Hi @flobernd ,

Thank you for pointing out the workaround. Not sure how I missed that. I definitely like that better than passing a string.

@braveyp
Copy link

braveyp commented Aug 22, 2024

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?

@ashitanojoe
Copy link
Contributor Author

I couldn't get the suggested workaround to work either, so I ended up using magic strings.

@flobernd
Copy link
Member

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!
            )
        )
    )
);

@braveyp
Copy link

braveyp commented Aug 23, 2024

Thanks for the help, that works perfectly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
8.x Relates to a 8.x client version Category: Feature Usability
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants