按 elasticsearch.net 中的字符串数组查询字符串数组
Querying array of strings by array of strings in elasticsearch.net
我在 C# 中使用 elasticsearch.net 库,我正在尝试查询与指定过滤器匹配的对象。
我想查询 return 个对象,其中至少一个来自过滤器的输入名称存在于对象的名称集合中。
问题是这个查询的结果我总是得到 0 个匹配,即使我确定数据库中确实存在与指定过滤器匹配的数据,我很想找出我的查询有什么问题...
型号:
public class A
{
public int AId { get; set; }
public IEnumerable<string> Names { get; set; }
}
过滤对象:
public class Filter
{
public IEnumerable<string> NamesToSearch { get; set; }
}
查询数据的方法:
public async Task<IEnumerable<A>> GetFilteredData(Filter filter)
{
var query = await _elasticClient.SearchAsync<A>(x => x.Query(q => q.Terms(a => a.Names, filter.NamesToSearch))
.Fields(a => a.AId, a => a.Names));
return query.Hits
.Select(x => new A
{
AId = x.Fields.FieldValues<A, int>(a => a.AId)[0]
})
.ToList();
}
我也试过以下查询,但也没有产生预期的结果:
var query = await _elasticClient.SearchAsync<A>(x => x.Query(q => q.Nested(n => n.Filter(f => f.Terms(y => y.Names, filter.NamesToSearch))))
.Fields(a => a.AId, a => a.Names));
对我有用的解决方案:
我已经将一些代码从 升级为实际使用 ElasticSearch.net 1.7.1 进行编译并且是类型安全的(不通过字符串引用字段名称)并以以下扩展方法结束,这对我的场景来说就像一个魅力:
public static QueryContainer MatchAnyTerm<T>(this QueryDescriptor<T> descriptor, Expression<Func<T, object>> field, object[] values) where T : class, new()
{
var queryContainer = new QueryContainer();
foreach (var value in values)
{
queryContainer |= descriptor.Term(t => t.OnField(field).Value(value));
}
return queryContainer;
}
和用法:
var query = await _elasticClient.SearchAsync<A>(x => x.Query(q =>
q.Bool(b =>
b.Should(s => s.MatchAnyTerm(a => a.Names, filter.NamesToSearch.ToArray()))
.Fields(a => a.AId, a => a.Names));
我认为你的问题是你试图将整个数组传递给查询。相反,您应该将其视为 OR 表达式。
以下是您应该使用的原始查询:
{
"query": {
"bool": {
"should": [
{ "term": {"names": "test" } },
{ "term": {"names": "xyz" } }
]
}
}
}
以及实现该目标的 C# 代码。首先我定义了辅助函数:
private static QueryContainer TermAny<T>(QueryContainerDescriptor<T> descriptor, Field field, object[] values) where T : class
{
QueryContainer q = new QueryContainer();
foreach (var value in values)
{
q |= descriptor.Term(t => t.Field(field).Value(value));
}
return q;
}
现在查询:
string[] values = new[] { "test", "xyz" };
client.Search<A>(x => x.Query(
q => q.Bool(
b => b.Should(s => TermAny(s, "names", values)))));
我在 C# 中使用 elasticsearch.net 库,我正在尝试查询与指定过滤器匹配的对象。
我想查询 return 个对象,其中至少一个来自过滤器的输入名称存在于对象的名称集合中。
问题是这个查询的结果我总是得到 0 个匹配,即使我确定数据库中确实存在与指定过滤器匹配的数据,我很想找出我的查询有什么问题...
型号:
public class A
{
public int AId { get; set; }
public IEnumerable<string> Names { get; set; }
}
过滤对象:
public class Filter
{
public IEnumerable<string> NamesToSearch { get; set; }
}
查询数据的方法:
public async Task<IEnumerable<A>> GetFilteredData(Filter filter)
{
var query = await _elasticClient.SearchAsync<A>(x => x.Query(q => q.Terms(a => a.Names, filter.NamesToSearch))
.Fields(a => a.AId, a => a.Names));
return query.Hits
.Select(x => new A
{
AId = x.Fields.FieldValues<A, int>(a => a.AId)[0]
})
.ToList();
}
我也试过以下查询,但也没有产生预期的结果:
var query = await _elasticClient.SearchAsync<A>(x => x.Query(q => q.Nested(n => n.Filter(f => f.Terms(y => y.Names, filter.NamesToSearch))))
.Fields(a => a.AId, a => a.Names));
对我有用的解决方案:
我已经将一些代码从
public static QueryContainer MatchAnyTerm<T>(this QueryDescriptor<T> descriptor, Expression<Func<T, object>> field, object[] values) where T : class, new()
{
var queryContainer = new QueryContainer();
foreach (var value in values)
{
queryContainer |= descriptor.Term(t => t.OnField(field).Value(value));
}
return queryContainer;
}
和用法:
var query = await _elasticClient.SearchAsync<A>(x => x.Query(q =>
q.Bool(b =>
b.Should(s => s.MatchAnyTerm(a => a.Names, filter.NamesToSearch.ToArray()))
.Fields(a => a.AId, a => a.Names));
我认为你的问题是你试图将整个数组传递给查询。相反,您应该将其视为 OR 表达式。
以下是您应该使用的原始查询:
{
"query": {
"bool": {
"should": [
{ "term": {"names": "test" } },
{ "term": {"names": "xyz" } }
]
}
}
}
以及实现该目标的 C# 代码。首先我定义了辅助函数:
private static QueryContainer TermAny<T>(QueryContainerDescriptor<T> descriptor, Field field, object[] values) where T : class
{
QueryContainer q = new QueryContainer();
foreach (var value in values)
{
q |= descriptor.Term(t => t.Field(field).Value(value));
}
return q;
}
现在查询:
string[] values = new[] { "test", "xyz" };
client.Search<A>(x => x.Query(
q => q.Bool(
b => b.Should(s => TermAny(s, "names", values)))));