【问题标题】:elasticsearch multimatch on nested items嵌套项目上的弹性搜索多重匹配
【发布时间】:2018-06-05 14:50:41
【问题描述】:

我从客户端得到一个字符串。此字符串可以匹配我的组中的一个字符串,或者一个底层项目的字符串之一。 这个字符串是必须查询的。

我得到了嵌套查询容器和普通查询容器的多重匹配。我的问题是:如何在单个多重匹配中同时获得嵌套层和顶层?

queryList.Add(q => q
            .MultiMatch(mm => mm
                .Fields(fs => fs
                    .Field(f => f.ExtraText)
                    .Field(f => f.SomeText)
                    .Field(f => f.MoreInfo)
                    .Field(f => f.SEOText)
                    .Field(f => f.Title))
                .Query(filter.SearchString)));
queryList.Add(q => q
            .Nested(c => c
                .Path(p => p.Items)
                .Query(nq => nq
                    .MultiMatch(mm => mm
                        .Fields(fs => fs
                            .Field(f => f.Items.First().Subtitle)
                            .Field(f => f.Items.First().Name)
                            .Field(f => f.Items.First().MoreInfo)
                            .Field(f => f.Items.First().ExtraText)
                            .Field(f => f.Items.First().SEOText))
                        .Query(filter.SearchString)))));

扩展: 此搜索查询是对现有号码过滤器的扩展。 在文本搜索旁边,还有类别或组来自哪个国家的过滤器:

if (filter.categories != null && filter.categories.Any())
        {
            foreach (string category in filter.categories)
            {
                queryList.Add(d => d
                    .Nested(nd => nd
                        .Path(np => np.Categories)
                        .Query(nq => nq
                            .Bool(nb => nb
                                .Must(fm => fm
                                    .Match(q => q
                                        .Field(f => f.Categories.First().UrlSlug)
                                        .Query(category)))))));
            }
        }
 if (!string.IsNullOrEmpty(filter.country))
        {
            queryList.Add(d => d.Term(p => p.country, filter.country));
        }

然后这个查询列表被提供给搜索:

 _elasticClient.Search<ProductModel>(d => d
                        .Index(_config.GroupIndexName)
                            .Query(q => q
                                .Bool(b => b.Must(queryList))
                            )
                            .Sort(s => s
                                .Field(f => f
                                    .Field(GetSortField(filter.SortOption))
                                    .Order(filter.SortOrder)
                                )
                            )
                            .Skip((filter.Page - 1) * filter.RecordsPerPage)
                            .Take(filter.RecordsPerPage)
                        );

我需要将搜索字符串过滤为 1 个单个查询。因此,在“必须”级别上,它们不会相互抵消。 (如果字符串与组匹配但不匹配他的基础项目之一,则两者都不会显示)。

【问题讨论】:

    标签: c# elasticsearch nest elasticsearch.net


    【解决方案1】:

    Use a bool query。看起来您可能希望将它们组合为 should 子句,即匹配一个 另一个查询

    client.Search<MyDocument>(s => s
        .Query(q => q
            .Bool(b => b
                .Should(sh => sh
                    .MultiMatch(mm => mm
                        .Fields(fs => fs
                            .Field(f => f.ExtraText)
                            .Field(f => f.SomeText)
                            .Field(f => f.MoreInfo)
                            .Field(f => f.SEOText)
                            .Field(f => f.Title)
                        )
                        .Query(filter.SearchString)
                    ), sh => sh
                    .Nested(c => c
                        .Path(p => p.Items)
                        .Query(nq => nq
                            .MultiMatch(mm => mm
                                .Fields(fs => fs
                                    .Field(f => f.Items.First().Subtitle)
                                    .Field(f => f.Items.First().Name)
                                    .Field(f => f.Items.First().MoreInfo)
                                    .Field(f => f.Items.First().ExtraText)
                                    .Field(f => f.Items.First().SEOText))
                                .Query(filter.SearchString)
                            )
                        )
                    )
                )
            )
        )
    );
    

    可以更简洁地表达

    client.Search<MyDocument>(s => s
        .Query(q => q
            .MultiMatch(mm => mm
                .Fields(fs => fs
                    .Field(f => f.ExtraText)
                    .Field(f => f.SomeText)
                    .Field(f => f.MoreInfo)
                    .Field(f => f.SEOText)
                    .Field(f => f.Title)
                )
                .Query(filter.SearchString)
            ) || q
            .Nested(c => c
                .Path(p => p.Items)
                .Query(nq => nq
                    .MultiMatch(mm => mm
                        .Fields(fs => fs
                            .Field(f => f.Items.First().Subtitle)
                            .Field(f => f.Items.First().Name)
                            .Field(f => f.Items.First().MoreInfo)
                            .Field(f => f.Items.First().ExtraText)
                            .Field(f => f.Items.First().SEOText))
                        .Query(filter.SearchString)
                    )
                )
            )
        )
    );
    

    【讨论】:

    • 我已经使用了布尔查询。这就是我创建查询的方式。问题是还有其他其他过滤器,例如必须级别的日期。因此,如果它在日期上被过滤,则应该被忽略。这就是为什么我在必须级别上使用多重匹配。
    • 根据您的问题和此评论,我不清楚您要达到的目标。您能否详细说明您的问题,或者添加客户调用的样子?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多