gpt4 book ai didi

c# - 如何在NEST中进行 Assets 汇总和/或组合?

转载 作者:行者123 更新时间:2023-12-02 23:01:49 29 4
gpt4 key购买 nike

背景

我要做什么

  • 我有车辆 list 。
  • 我有一个API(WebAPI v2),该API接受用于品牌和型号的过滤器列表
  • 过滤器包含1个品牌和0个或多个模型。 (例如“本田”和“[思域”,“雅阁”]))
  • 如果通过带有make且没有模型的过滤器,我希望它与该make的所有模型匹配。
  • 如果过滤器随品牌和型号一起传递,我希望它仅针对该品牌制作那些型号。

  • 我正在使用的过滤器对象
    public class MakeModelFilter : IMakeModelFilter
    {
    public string Make { get; set; }
    public List<string> Models { get; set; }
    }

    整个API调用看起来像什么
    {
    "MakeModelFilters": [
    {"Make": "BMW", "Models": ["X3", "X5"]}
    ],
    "TypeFilter": [],
    "GenericColorFilter": [],
    "FeaturesFilter": [],
    "MaxMileage" : 100000,
    "PriceRange": {"Min": 1, "Max": 1000000},
    "SearchText": ""
    }

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

    我目前如何获得搜索结果:
    var vehicles = _esClient.Search<Vehicle>(s => s
    .From(0).Size(10000)
    .Query(q => q
    .Filtered(fq => fq
    .Filter(ff => ff
    .Bool(b => b
    .Must(m=> m.And(
    m.Or(makeModelFilterList.ToArray()),
    m.Or(featureFilters.ToArray()),
    m.Or(typeFilters.ToArray()),
    priceRangeFilter,
    mileageFilter))
    )
    )
    .Query(qq => qq
    .QueryString(qs => qs.Query(criteria.SearchText))
    )
    )
    )
    );

    问题

    无论我如何构造过滤器,它似乎都会过滤掉所有文档,这与我们的最大利益无关。 :)我的 bool(boolean) 逻辑有些错误。

    我认为问题出在哪里

    or在一起的品牌和型号过滤器列表是通过以下方法生成的:
    private List<FilterContainer> GenerateMakeModelFilter(List<MakeModelFilter> makeModelFilters)
    {
    var filterList = new List<FilterContainer>();
    foreach (var filter in makeModelFilters)
    {
    filterList.Add(GenerateMakeModelFilter(filter));
    }

    return filterList;
    }

    此方法调用单个方法为我拥有的每个品牌/型号过滤器生成 bool(boolean) 值。

    我认为问题的方法是

    据我所知,以下方法将执行以下操作:
  • 如果没有传递make,则抛出异常
  • 如果仅传入一个make,则仅返回该make的 bool(boolean) 值。
  • 如果传入了制造商和模型,则返回制造商过滤器的 bool(boolean) 值+所有模型项的or。例如Make:BMW AND (model:X3 OR model: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}};
    }

    仅供引用, GenerateFilterList仅创建术语过滤器列表并返回该列表。

    仅供引用:生成的ElasticSearch JSON

    这可能是我要去哪里的线索(尽管它很大)。我一直盯着它看了很久,以至于我看不到它。
    {
    "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"

    }
    }
    }
    ]
    }
    }
    ]
    }
    }
    }
    }
    }

    重构1:向位操作进一步移动

    根据Martijn的答案和他引用的 Zachary's post,我已经更新了 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;
    }

    然后针对 GenerateMakeModelFilter,对“模型过滤器”执行“与”操作,该操作应按位或基于上述代码:
    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>();

    ...但是我仍然没有文档返回。我到底想念什么?如果我有一个带有“思域”和“雅阁”型号的本田品牌,而没有一个没有模型的“宝马”品牌,则我应该收到所有装有本田+思域的车辆。本田+雅阁||宝马+(任何型号)。我会坚持下去。

    最佳答案

    和/或,而不是过滤器可能无法满足您的要求。它们是一种特殊的过滤器构造,当组合对位集不起作用的过滤器时,性能会更好。必须阅读以下主题:

    https://www.elastic.co/blog/all-about-elasticsearch-filter-bitsets

    知道何时使用过滤器和/或不使用过滤器与 bool(boolean) 过滤器可能会造成很大的混淆,在Elasticsearch 2.0中,您可以在所有上下文中使用 bool(boolean) 过滤器,它将知道如何在其子句中最佳地执行过滤器/查询。不再需要您提示!

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

    这就是为什么bool子句必须/应该/必须不vs和/或/不。

    在NEST中,如果将&&||!运算符与括号结合使用,我们将组成一个或多个 bool(boolean) 查询,以便其以二进制 bool(boolean) 方式起作用,即用C#编写下来。

    例如:

    .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;
    }

    同样,如果您重构 GenerateMakeModelFilter以利用C# bool(boolean) 运算符重载,您最终将获得更易于阅读和调试的查询。就C#以及发送到Elasticsearch的查询而言。

    我们的文档更加详细地介绍了它 http://nest.azurewebsites.net/nest/writing-queries.html

    更新

    很棒的重构!现在我们可以专注于Elasticsearch中的映射。当您为json属性建立索引时,它会通过 an analysis chain接受单个字符串,并尝试从中做出1个或多个要存储在lucene反向索引中的术语。

    默认情况下,elasticsearch将使用 standard analyzer分析所有字符串字段

    在您的情况下, BMW将通过 standard analyzer,它将在空格( Unicode standard annex #29 to be exact)上分割并小写。

    因此,反向索引中的术语为 bmw。在Elasticsearch中,一些查询也在查询时进行了分析,因此在查询反向索引之前还分析了 BMWa match query,并将其转换为 bmw,因此无论查询时使用 BMW的大小写,都将找到文档。

    您正在使用的查询/过滤器一词是 而不是在查询时进行了分析,因此它将尝试在倒排索引中查找 BMW,而倒排索引中只有 bmw。如果您只需要精确的术语匹配,那就太好了。如果您设置 your mapping以便不分析某个字段,则可以例如对 New York进行完全匹配,而不必担心其实际存储为两个单独的词 newyork,并且无意间也会从 New New York获取结果

    关于c# - 如何在NEST中进行 Assets 汇总和/或组合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32551625/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com