在elasticsearch.net中按字符串数组查询字符串数组

编程入门 行业动态 更新时间:2024-10-26 23:25:40
本文介绍了在elasticsearch中按字符串数组查询字符串数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我在C#中使用elasticsearch库,并且试图查询与指定过滤器匹配的对象.

我希望查询返回对象,其中对象的Names集合中至少存在来自过滤器的输入名称之一.

问题在于,此查询的结果总是使我命中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));

为我工作的解决方案:

我已经从SławomirRosiek的答案升级了一些代码,以使用ElasticSearch 1.7.1进行实际编译并输入-safe(不按字符串引用字段名称),并以以下扩展方法结束,这种扩展方法在我的情况下就像一个魅力:

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)))));

I'm using elasticsearch library in C# and I'm trying to query for objects matching specified filter.

I would like the query to return objects where at least one of input names from filter exists in object's Names collection.

The problem is that I always get 0 hits as result with this query, even tho I am certain that data matching specified filter does exist in the database and I would love to find out what's wrong with my query...

The model:

public class A { public int AId { get; set; } public IEnumerable<string> Names { get; set; } }

The filtering object:

public class Filter { public IEnumerable<string> NamesToSearch { get; set; } }

The method for querying data:

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(); }

I have also tried following query, but it didn't yield expected result neither:

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));

SOLUTION WHICH WORKED FOR ME:

I have upgraded a bit code from Sławomir Rosiek's answer to actually compile using ElasticSearch 1.7.1 and be type-safe (no references to field name by string) and ended up with following extension method, which worked like a charm for my scenario:

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

and usage:

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));

解决方案

I think that your problem is that you tries to pass whole array to query. Instead of that you should treat that as OR expression.

Below is the raw query that you should use:

{ "query": { "bool": { "should": [ { "term": {"names": "test" } }, { "term": {"names": "xyz" } } ] } } }

And that the C# code to achive that. First I have defined helper function:

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

And now the query:

string[] values = new[] { "test", "xyz" }; client.Search<A>(x => x.Query( q => q.Bool( b => b.Should(s => TermAny(s, "names", values)))));

更多推荐

在elasticsearch.net中按字符串数组查询字符串数组

本文发布于:2023-10-22 08:41:30,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1517012.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:数组   字符串   elasticsearch   net

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!