我在玩 Elasticsearch 和 NEST。
我确实很难理解可用于创建和构建静态查询的各种类和接口。
这是我想要实现的简化示例:
using Nest;
using System;
using System.Text;
namespace NestTest
{
public class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
public class ProductFilter
{
public string[] IncludeNames { get; set; }
public string[] ExcludeNames { get; set; }
public int MaxPrice { get; set; }
}
class Program
{
static void Main(string[] args)
{
var filter = new ProductFilter();
filter.MaxPrice = 100;
filter.IncludeNames = new[] { "Notebook", "Workstation" };
filter.ExcludeNames = new[] { "Router", "Modem" };
var query = CreateQueryFromFilter(filter);
var client = new ElasticClient();
// Test Serialization
var serialized = Encoding.UTF8.GetString(client.Serializer.Serialize(query));
Console.WriteLine(serialized);
// TODO: How to convert the IQuery to QueryContainer?
//client.Search<Product>(s => s.Query(q => query));
}
private static IQuery CreateQueryFromFilter(ProductFilter filter)
{
var baseBoolean = new BoolQueryDescriptor<Product>();
if (filter.IncludeNames != null && filter.IncludeNames.Length > 0)
{
foreach (var include in filter.IncludeNames)
{
// TODO: This overwrites the previous must
baseBoolean.Must(q => q.Term(t => t.Name, include));
}
}
if (filter.ExcludeNames != null && filter.ExcludeNames.Length > 0)
{
foreach (var exclude in filter.ExcludeNames)
{
// TODO: This overwrites the previous must
baseBoolean.MustNot(q => q.Term(t => t.Name, exclude));
}
}
if (filter.MaxPrice > 0)
{
// TODO: This overwrites the previous must
baseBoolean.Must(q => q.Range(r => r.LowerOrEquals(filter.MaxPrice).OnField(f => f.Price)));
}
return baseBoolean;
}
}
}
如您所见,我想创建某种查询对象(很可能是 BoolQuery),然后稍后填充该对象。我在遇到实际问题的代码中添加了一些 TODOS。但总的来说,有太多的可能性(IQuery、QueryContainer、XXXQueryDescriptor、SearchDescriptor、SearchRequest),我无法弄清楚如何成功地逐部分“构建”查询。
有哪位大侠能赐教吗?
组合布尔查询在此处的文档中进行了描述:
http://nest.azurewebsites.net/nest/writing-queries.html
该页面略有过时,将很快更新,尽管其中大部分仍然适用我更新了您的
CreateQueryFromFilter
方法以展示您可以制定查询的几种方式:
private static IQueryContainer CreateQueryFromFilter(ProductFilter filter)
{
QueryContainer queryContainer = null;
if (filter.IncludeNames != null && filter.IncludeNames.Length > 0)
{
foreach (var include in filter.IncludeNames)
{
//using object initializer syntax
queryContainer &= new TermQuery()
{
Field = Property.Path<Product>(p => p.Name),
Value = include
};
}
}
if (filter.ExcludeNames != null && filter.ExcludeNames.Length > 0)
{
foreach (var exclude in filter.ExcludeNames)
{
//using static Query<T> to dispatch fluent syntax
//note the ! support here to introduce a must_not clause
queryContainer &= !Query<Product>.Term(p => p.Name, exclude);
}
}
if (filter.MaxPrice > 0)
{
//fluent syntax through manually newing a descriptor
queryContainer &= new QueryDescriptor<Product>()
.Range(r => r.LowerOrEquals(filter.MaxPrice).OnField(f => f.Price)
);
}
return queryContainer;
}
以下是将其传递给搜索操作的方法:
static void Main(string[] args)
{
//using the object initializer syntax
client.Search<Product>(new SearchRequest()
{
Query = query
});
//using fluent syntax
client.Search<Product>(s => s.Query(query));
}
NEST
有很多更新,现在您可以使用Infer
访问Field
(使用NEST 7.17.5检查):
var query = new MatchQuery
{
Query = "name of product",
Field = Infer.Field<Product>(p => p.Name),
};
PS:现在库重命名为:Elastic.Clients.Elasticsearch.