通过elasticsearch.net中的字符串数组查询字符串数组 [英] Querying array of strings by array of strings in elasticsearch.net

查看:36
本文介绍了通过elasticsearch.net中的字符串数组查询字符串数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

问题是我总是通过这个查询得到 0 个命中,即使我确定数据库中确实存在与指定过滤器匹配的数据,我很想找出我的查询有什么问题......

型号:

公共类A{公共 int AId { 获取;放;}公共 IEnumerable名称 { 得到;放;}}

过滤对象:

公共类过滤器{公共 IEnumerableNamesToSearch { 获取;放;}}

查询数据的方法:

public async Task>GetFilteredData(过滤器过滤器){var query = await _elasticClient.SearchAsync(x => x.Query(q => q.Terms(a => a.Names, filter.NamesToSearch)).Fields(a => a.AId, a => a.Names));返回 query.Hits.Select(x => new A{AId = x.Fields.FieldValues(a => a.AId)[0]}).ToList();}

我也尝试过以下查询,但也没有产生预期的结果:

var query = await _elasticClient.SearchAsync(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ławomir Rosiek 的答案 升级了一些代码,以便使用 ElasticSearch.net 1.7.1 进行实际编译并输入-safe(没有通过字符串引用字段名称)并以以下扩展方法结束,这对我的场景来说就像一个魅力:

public static QueryContainer MatchAnyTerm(this QueryDescriptor descriptor, Expression> field, object[] values) where T : class, new(){var queryContainer = new QueryContainer();foreach(值中的 var 值){queryContainer |= descriptor.Term(t => t.OnField(field).Value(value));}返回查询容器;}

和用法:

var query = await _elasticClient.SearchAsync(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 表达式.

以下是您应该使用的原始查询:

<代码>{询问": {布尔":{应该": [{ "term": {"names": "test" } },{ "term": {"names": "xyz" } }]}}}

实现这一目标的 C# 代码.首先我定义了辅助函数:

private static QueryContainer TermAny(QueryContainerDescriptor descriptor, Field field, object[] values) where T : class{QueryContainer q = new QueryContainer();foreach(值中的 var 值){q |= descriptor.Term(t => t.Field(field)).Value(value));}返回 q;}

现在查询:

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

I'm using elasticsearch.net 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.net 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中的字符串数组查询字符串数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆