elasticsearch,filter,boolean-logic,nest,C#,elasticsearch,Filter,Boolean Logic,Nest" /> elasticsearch,filter,boolean-logic,nest,C#,elasticsearch,Filter,Boolean Logic,Nest" />

C# 如何在NEST中进行属性汇总和/或组合? 背景 我想做什么 我有一份车辆清单 我有一个API(WebAPI v2),它接受了一个make和models的过滤器列表 过滤器由1个品牌和0个或更多型号组成。(例如“本田”和[“思域”、“雅阁]) 如果传入一个带有make而没有模型的过滤器,我希望它匹配该make的所有模型 如果传入一个带有make和models的过滤器,我希望它只生成该make的那些模型 我正在使用的过滤器对象

C# 如何在NEST中进行属性汇总和/或组合? 背景 我想做什么 我有一份车辆清单 我有一个API(WebAPI v2),它接受了一个make和models的过滤器列表 过滤器由1个品牌和0个或更多型号组成。(例如“本田”和[“思域”、“雅阁]) 如果传入一个带有make而没有模型的过滤器,我希望它匹配该make的所有模型 如果传入一个带有make和models的过滤器,我希望它只生成该make的那些模型 我正在使用的过滤器对象,c#,elasticsearch,filter,boolean-logic,nest,C#,elasticsearch,Filter,Boolean Logic,Nest,我关心的部分是MakeAndModelFilters列表(其余部分按照当前的设计工作) 我当前获取搜索结果的方式: 此方法调用单个方法为我拥有的每个make/model过滤器生成bool 我认为问题的解决方法是 据我所知,以下方法执行以下操作: 如果没有传入make,则抛出异常 如果只传入一个make,则只返回该make的bool 如果传入make和models,则返回make过滤器的a bool+所有model项的或。e、 g.品牌:宝马和(型号:X3或型号:X5) 代码如下: priva

我关心的部分是MakeAndModelFilters列表(其余部分按照当前的设计工作)

我当前获取搜索结果的方式: 此方法调用单个方法为我拥有的每个make/model过滤器生成bool

我认为问题的解决方法是 据我所知,以下方法执行以下操作:

  • 如果没有传入make,则抛出异常
  • 如果只传入一个make,则只返回该make的bool
  • 如果传入make和models,则返回make过滤器的a bool+所有model项的
    。e、 g.
    品牌:宝马和(型号:X3或型号:X5)
代码如下:

private FilterContainer GenerateMakeModelFilter(MakeModelFilter makeModelFilter)
{
    if (string.IsNullOrWhiteSpace(makeModelFilter.Make)) { throw new ArgumentNullException(nameof(makeModelFilter));}

    var makeFilter = new TermFilter { Field = Property.Path<Vehicle>(it => it.Make), Value = makeModelFilter.Make };
    var boolMake = new BoolFilter { Must = new List<FilterContainer> { makeFilter } };

    var modelFilters = GenerateFilterList(Property.Path<Vehicle>(it => it.Model), makeModelFilter.Models);

    if (!modelFilters.Any())
    {
        // If it has a make but no model, generate boolFilter make only.
        return boolMake;
    }

    var orModels = new OrFilter {Filters = modelFilters};
    var boolModels = new BoolFilter {Must = new List<FilterContainer> {orModels}};

    var boolMakeAndModels = new AndFilter {Filters = new List<FilterContainer> {boolMake, boolModels}};

    return new BoolFilter {Must = new List<FilterContainer> {boolMakeAndModels}};
}
重构1:更倾向于按位操作 根据Martijn的回答以及他引用的内容,我已经更新了我的
GenerateFilterList
,以返回一个串联的filterContainer:

private FilterContainer GenerateFilterList(PropertyPathMarker path, List<string> filter)
{
    if (filter == null || filter.Count <= 0){ return null; }

    FilterContainer returnFilter = null;
    foreach (var aFilter in filter)
    {
        returnFilter |= new TermFilter {Field = path, Value = aFilter.ToLowerInvariant()};
    }

    return returnFilter;
}
这将缩短检索查询的部分:

QueryContainer textQuery = new QueryStringQuery() {Query = criteria.SearchText };
FilterContainer boolFilter = makeModelFilter || featureFilter || typeFilter || priceRangeFilter || mileageFilter;

var vehicles = _esClient.Search<Vehicle>(s => s
.From(0).Size(10000) //TODO: Extract this into a constant or setting in case the inventory grows to 10k+. This prevents it from paging.
.Query(q => q
    .Filtered(fq => fq
        .Filter(filter => filter.Bool(bf => bf.Must(boolFilter)))
        .Query(qq => textQuery)
        )
    )   
);

return vehicles.Documents.ToList<IVehicle>();
QueryContainer textQuery=newquerystringquery(){Query=criteria.SearchText};
FilterContainer boolFilter=makeModelFilter | | | featureFilter | | typeFilter | | priceRangeFilter | | mileageFilter;
var vehicles=\u esClient.Search(s=>s
.From(0).Size(10000)//TODO:将其提取到常量或设置中,以防库存增长到10k+。这会阻止它分页。
.Query(q=>q
.已筛选(fq=>fq
.Filter(Filter=>Filter.Bool(bf=>bf.Must(boolFilter)))
.Query(qq=>textQuery)
)
)   
);
返回车辆.文件.ToList();

…但我仍然没有返回任何文档。我到底错过了什么?如果我有一个本田品牌,车型为“思域”和“雅阁”,而一个品牌为“宝马”,没有车型,我应该收到所有本田+思域| |本田+雅阁|宝马+(任何车型)的车辆。我会坚持下去。

和,或,¬过滤器可能无法满足您的需要。它们是一种特殊的过滤器结构,在组合不在位集上运行的过滤器时性能更好。必须阅读此主题:

知道何时使用和/或/或不使用过滤器与布尔过滤器可能会非常混乱,使用Elasticsearch 2.0,您可以在所有上下文中使用布尔过滤器,它将知道如何最好地执行其子句中的过滤器/查询。你再也不需要暗示了

此外,尽管bool过滤器/查询名为bool,但它是一元bool,而您可能希望它是二进制bool

这就是为什么bool条款是必须/应该/必须不vs和/或不

如果使用
&&
| |
,则在嵌套中运算符与括号组合我们将组合一个或多个bool查询,以便它以二进制bool方式运行,您可以用C#写下它

e、 g:

如果需要更动态的列表,可以使用赋值运算符
=
&=

private FilterContainer GenerateMakeModelFilter(List<MakeModelFilter> makeModelFilters)
{
    FilterContainer filter = null;
    foreach (var filter in makeModelFilters)
    {
        filter |= GenerateMakeModelFilter(filter);
    }

    return filter;
}
private filter container GenerateMakeModelFilter(列出MakeModelFilter)
{
FilterContainer筛选器=空;
foreach(makeModelFilters中的var过滤器)
{
过滤器|=发电机模型过滤器(过滤器);
}
回流过滤器;
}
类似地,如果您重构
GenerateMakeModelFilter
以利用C#boolean运算符重载,您将得到一个更易于阅读和调试的查询。在C#以及发送到Elasticsearch的查询方面

我们的文档更详细地介绍了它

更新

真棒的重构!现在我们可以关注elasticsearch中的映射。当你索引一个json属性时,它会通过一个字符串并尝试从中提取一个或多个术语,这些术语将存储在lucene的反向索引中

默认情况下,elasticsearch将使用

在您的情况下,
BMW
将通过在空格()和小写上拆分的

因此,反向索引中的术语是
bmw
。在elasticsearch中,一些查询也会在查询时进行分析,因此在查询倒排索引之前,例如对于
BMW
也会进行分析并转换为
BMW
,因此无论
BMW
的大小写如何,都会在查询时查找文档


您使用的术语查询/过滤器在查询时未进行分析,因此它将尝试在反向索引中查找
BMW
,其中反向索引只有
BMW
。这是伟大的,如果你只想确切的条款匹配。例如,如果您设置为不分析某个字段,您可以在纽约进行精确匹配,而不必担心其实际存储为两个单独的术语,即纽约和纽约,并且无意中也会从中获得结果。另外,PS:如果我取出make/model组合,只对模型上的一个
,它按预期工作。所以我认为这一定是品牌和型号之间的一种组合。谢谢你的参与!Zachary关于您引用的位集的博文中有一个很大的免责声明,说它不再是推荐的建议。我应该不担心吗?在阅读了这篇博文之后,我在问题中添加了更新1,并针对您的解决方案进行了重构。然而,我似乎仍然没有返回任何文件。如有进一步了解,将不胜感激。我不知道为什么它没有点击。谢谢还为我的答案添加了一个更新。扎克的博客文章不再适用于2.0(试用版)
private FilterContainer GenerateMakeModelFilter(MakeModelFilter makeModelFilter)
{
    if (string.IsNullOrWhiteSpace(makeModelFilter.Make)) { throw new ArgumentNullException(nameof(makeModelFilter));}

    var makeFilter = new TermFilter { Field = Property.Path<Vehicle>(it => it.Make), Value = makeModelFilter.Make };
    var boolMake = new BoolFilter { Must = new List<FilterContainer> { makeFilter } };

    var modelFilters = GenerateFilterList(Property.Path<Vehicle>(it => it.Model), makeModelFilter.Models);

    if (!modelFilters.Any())
    {
        // If it has a make but no model, generate boolFilter make only.
        return boolMake;
    }

    var orModels = new OrFilter {Filters = modelFilters};
    var boolModels = new BoolFilter {Must = new List<FilterContainer> {orModels}};

    var boolMakeAndModels = new AndFilter {Filters = new List<FilterContainer> {boolMake, boolModels}};

    return new BoolFilter {Must = new List<FilterContainer> {boolMakeAndModels}};
}
{
  "from": 0,
  "size": 10000,
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "and": {
                "filters": [
                  {
                    "or": {
                      "filters": [
                        {
                          "bool": {
                            "must": [
                              {
                                "and": {
                                  "filters": [
                                    {
                                      "bool": {
                                        "must": [
                                          {
                                            "term": {
                                              "make": "BMW"
                                            }
                                          }

                                        ]
                                      }
                                    },
                                    {
                                      "bool": {
                                        "must": [
                                          {
                                            "or": {
                                              "filters": [
                                                {
                                                  "term": {
                                                    "model": "x3"
                                                  }
                                                },
                                                {
                                                  "term": {
                                                    "model": "x5"
                                                  }
                                                }

                                              ]
                                            }
                                          }
                                        ]
                                      }
                                    }
                                  ]
                                }
                              }
                            ]
                          }
                        }
                      ]
                    }
                  },
                  { },
                  { },
                  {
                    "range": {
                      "sellingPriceUSD": {
                        "lte": "1000000",
                        "gte": "1"
                      }
                    }
                  },
                  {
                    "range": {
                      "miles": {
                        "lte": "100000"

                      }
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }
}
private FilterContainer GenerateFilterList(PropertyPathMarker path, List<string> filter)
{
    if (filter == null || filter.Count <= 0){ return null; }

    FilterContainer returnFilter = null;
    foreach (var aFilter in filter)
    {
        returnFilter |= new TermFilter {Field = path, Value = aFilter.ToLowerInvariant()};
    }

    return returnFilter;
}
private FilterContainer GenerateMakeModelFilter(MakeModelFilter makeModelFilter)
{
    if (string.IsNullOrWhiteSpace(makeModelFilter.Make)) { throw new ArgumentNullException(nameof(makeModelFilter)); }

    var makeFilter = new TermFilter { Field = Property.Path<Vehicle>(it => it.Make), Value = makeModelFilter.Make };

    var modelFilters = GenerateFilterList(Property.Path<Vehicle>(it => it.Model), makeModelFilter.Models);

    return makeFilter && modelFilters;
}
QueryContainer textQuery = new QueryStringQuery() {Query = criteria.SearchText };
FilterContainer boolFilter = makeModelFilter || featureFilter || typeFilter || priceRangeFilter || mileageFilter;

var vehicles = _esClient.Search<Vehicle>(s => s
.From(0).Size(10000) //TODO: Extract this into a constant or setting in case the inventory grows to 10k+. This prevents it from paging.
.Query(q => q
    .Filtered(fq => fq
        .Filter(filter => filter.Bool(bf => bf.Must(boolFilter)))
        .Query(qq => textQuery)
        )
    )   
);

return vehicles.Documents.ToList<IVehicle>();
.Query(q=>q
    (q.Term("language", "php")
        && !q.Term("name", "Elastica")
    )
    ||
    q.Term("name", "NEST")
)
private FilterContainer GenerateMakeModelFilter(List<MakeModelFilter> makeModelFilters)
{
    FilterContainer filter = null;
    foreach (var filter in makeModelFilters)
    {
        filter |= GenerateMakeModelFilter(filter);
    }

    return filter;
}