Добавление нескольких логических фильтров к запросу NEST

Я хотел бы добавить несколько логических фильтров с помощью NEST, но я не могу (практически) сделать это в одном выражении, поскольку я хочу создать набор фильтров Bool в зависимости от различных условий.

Что-то вроде этого псевдокода:

// Append a filter
searchDescriptor.Filter(f => f.Bool(b => b.Must(m => m.Term(i => i.SomeProperty, "SomeValue"))));

if (UserId.HasValue)
{
   // Optionally append another filter (AND condition with the first filter)
   searchDescriptor.Filter(f => f.Bool(b => b.Must(m => m.Term(i => i.AnotherProperty, "MyOtherValue"))));
}

var result = Client.Search(searchDescriptor);

Теперь кажется, что когда добавляется второй необязательный фильтр, он по существу заменяет первый фильтр.

Я уверен, что я что-то упускаю синтаксически, но я не могу понять это, а документация NEST немного тонкая по фильтру DSL. :)


person Ted Nyberg    schedule 28.10.2013    source источник


Ответы (2)


Раздел о написании запросов в значительной степени относится и к фильтрам: https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/writing-queries.html

Решение, с которым вы столкнулись, далеко не идеальное, поскольку вы оборачиваете фильтры bool внутри фильтра and, которые имеют очень разные механизмы кэширования (и фильтры не используют кэшированные наборы битов, поэтому в большинстве случаев работают хуже, чем обычные логические фильтры).

Настоятельно рекомендуем прочитать http://www.elastic.co/blog/all-about-elasticsearch-filter-bitsets/, поскольку он очень хорошо объясняет, в чем разница между фильтрами и/или/не фильтрами и логическими фильтрами.

На самом деле вы можете переписать это так:

Client.Search(s=>s
    .Filter(f=> { 
        BaseFilter ff = f.Term(i => i.MyProperty, "SomeValue");
        if (UserId.HasValue)
            ff &= f.Term(i => i.AnotherProperty, "AnotherValue");
        return ff;
    })
);

Если второй термин ищет с использованием UserId, вы можете воспользоваться преимуществами conditionless queries NEST.

Client.Search(s=>s
    .Filter(f=> 
        f.Term(i => i.MyProperty, "SomeValue") 
        && f.Term(i => i.AnotherProperty, UserId)
    )
);

Если UserId равно null, то запрос терма не будет генерироваться как часть запроса, в этом случае вложение даже не будет оборачивать единственный оставшийся термин в логический фильтр, а вместо этого просто отправит его как фильтр простого термина.

person Martijn Laarman    schedule 03.11.2013

Ах, что-то вроде этого, кажется, работает:

        var filters = new List<BaseFilter>();

        // Required filter
        filters.Add(new FilterDescriptor<MyType>().Bool(b => b.Must(m => m.Term(i => i.MyProperty, "SomeValue"))));

        if (UserId.HasValue)
        {
            filters.Add(new FilterDescriptor<MyType>().Bool(b => b.Must(m => m.Term(i => i.AnotherProperty, "AnotherValue"))));
        }

        // Filter with AND operator
        searchDescriptor.Filter(f => f.And(filters.ToArray()));

        var result = Client.Search(searchDescriptor);
person Ted Nyberg    schedule 28.10.2013