2

Using the Elasticsearch NEST library for .NET I am trying to create a query that will search for products. The model's structure is the following:

[ElasticsearchType(Name = "product", IdProperty = "ProductId")]
public class ProductIndex
{
    [Number(NumberType.Integer)]
    public int ProductId { get; set; }

    [Text]
    public string Name { get; set; }

    [Text]
    public string Description { get; set; }

    [Number(NumberType.Integer)]
    public int BranchId { get; set; }

    [Number(NumberType.Integer)]
    public int SubbranchId { get; set; }

    [Number(NumberType.Float)]
    public decimal Rating { get; set; }

    [Boolean]
    public bool IsActive { get; set; }

    [Date]
    public DateTime PublishedAt { get; set; }

    [Nested]
    public ICollection<VariantIndex> Variants { get; set; }
}

[ElasticsearchType(Name = "variant", IdProperty = "VariantId")]
public class VariantIndex
{
    public int VariantId { get; set; }
    public decimal Price { get; set; }
    public IEnumerable<string> Values { get; set; }
}

I need to filter the products according to the following parameters:

  • branchId (int): the product BranchId equals to the branchId parameter,
  • subbranches (int[]): the product SubbranchId is contained in the subbranches array
  • rating (int): the product Rating is greater than or equal to the rating parameter
  • minPrice (int): the product variants Price is greater than minPrice parameter
  • maxPrice (int): the product variants Price is less than maxPrice parameter
  • searchTerm (string): the product Name or Description contain the string searchTerm
  • tags (string[]): the product variants Values contains one or more or all tags.

NOTE: The branchId, subbranches, rating and searchTerm should filter out the top level ProductIndex objects. Then, the minPrice and maxPrice parameters should filter out any nested Variants objects if their Price is not in the specified range and finally the tags parameter should filter out any nested Variants object that do not contain any of the tags in their Values array or score them appropriately according to the number of tags that matched in the Values array.

The end result should be a list of scored ProductIndex objects, each containing a list of filtered out and scored VariantIndex objects.


Here is how i tried to create the query but this gives me totally wrong search results:

Func<SearchDescriptor<ProductIndex>, ISearchRequest> search = s => s
            .From(page * 10)
            .Size(10)
            .Query(q => q
                .Bool(b => b
                    .Must(mu => mu
                        .Match(m => m
                            .Field(f => f.Name)
                            .Query(searchTerm)
                        ), mu => mu
                        .Match(m => m
                            .Field(f => f.Description)
                            .Query(product)
                        ), mu => mu
                        .Terms(t => t
                            .Field(f => f.Variants.Select(v => v.Values))
                            .Terms(tags)
                        )
                    )
                    .Filter(bf => bf
                        .Term(t => t
                        .Field(p => p.BranchId)
                        .Value(mainbranch))
                     )
                    .Filter(bf => bf
                            .Terms(t => t
                            .Field(p => p.SubbranchId)
                            .Terms(subbranches)
                        )
                    )
                    .Filter(bf => bf
                        .Range(r => r
                            .Field(f => f.Variants.Select(v => v.Price))
                            .GreaterThanOrEquals(minPrice)
                            .LessThanOrEquals(maxPrice)
                        )
                    )
                )
            );


        var response = await client.SearchAsync<ProductIndex>(search);

EDIT 1: Based on the comments my own investigation I finally managed to create a query which works correctly. The only thing left to do is to filter out the list of nested VariantIndex objects so that we only get the variants which comply with the price and tags filters. What code should I add to my latest working version of the query in order to achieve this?

Func<SearchDescriptor<ProductIndex>, ISearchRequest> search = s => s.Type<ProductIndex>()
            .Query(q => q
                .Bool(b => b
                    .Must(m => m
                        .MultiMatch(mm => mm
                            .Query(product)
                            .Fields(f =>
                                f.Fields(f1 => f1.Name, f2 => f2.Description)
                            )
                        )
                    )
                    .Should(ss => ss
                        .Match(m => m
                            .Field(f => f.Variants.Select(v => v.Values))
                            .Query(tagsJoined)
                        )
                    )
                    .Filter(m => m
                        .Bool(bl => bl
                            .Must(ms => ms
                                .Range(r => r
                                    .Field(f => f.Rating)
                                    .GreaterThanOrEquals(rating)
                                ),
                                ms => ms
                                    .Range(r => r
                                        .Field(f => f.Variants.Select(v => v.Price))
                                        .GreaterThanOrEquals(minPrice)
                                        .LessThanOrEquals(maxPrice)
                                    )
                            )
                        )

                    )
                )

            )
Dejan Bogatinovski
  • 610
  • 1
  • 6
  • 21
  • What results are returned from your current query? – Brad Crandell Aug 23 '17 at 12:09
  • In the response I get a list of product indexes (List) and the problem is that the list contains ProductIndex objects who's BranchId is equal to 5 for example, but In my query the branchId parameter equals to 10. The same is true for all the other properties. The only parameter that is applied correctly is the searchTerm which gives me only the ProductIndex objects that contain that searchTerm in the Description field – Dejan Bogatinovski Aug 23 '17 at 12:20
  • 1
    The three `bool` query `filter` clauses should be supplied as arguments to one `.Filter(...)` call, similar to the call to `.Must()`. – Russ Cam Aug 23 '17 at 22:53
  • @RussCam I Managed to get a working version of my query, thank you for your suggestion. Please read my EDIT section since there is one more thing left to do with the query. – Dejan Bogatinovski Aug 24 '17 at 08:05

0 Answers0