通过elasticsearch.net中的字符串数组查询字符串数组

Posted

技术标签:

【中文标题】通过elasticsearch.net中的字符串数组查询字符串数组【英文标题】:Querying array of strings by array of strings in elasticsearch.net 【发布时间】:2016-04-02 13:39:40 【问题描述】:

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

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

问题是我总是得到 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ławomir Rosiek's answer 升级了一些代码,以使用 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));

【问题讨论】:

您也可以使用Terms() 查询/过滤器来实现此目的,传递至少一个应该匹配的术语数组。 @RussCam 是的,我试过了,它产生了 0 次点击,就像我上面描述的那样。 您使用的是哪个版本的 NEST 以及您运行的是哪个版本的 Elasticsearch? 【参考方案1】:

我认为您的问题是您尝试将整个数组传递给查询。相反,您应该将其视为 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)))));

【讨论】:

感谢您的回答,非常有帮助。我稍微修改了您的代码以使其正常工作,因为在我使用的 elasticsearch.net 版本(v. 1.7.1)中找不到类型“QueryContainerDescriptor”和“Field”。

以上是关于通过elasticsearch.net中的字符串数组查询字符串数组的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch.net 客户端无法进行基本搜索

字符串中的 Rs 数

Elasticsearch.Net.UnexpectedElasticsearchClientException:在从 ES 获取数据期间

如何在C++中 统计多行文本中的行数、单词数及字符数

如何在 C++ 中的同一函数中使用字符串和双精度数

是否有 Perl 快捷方式来计算字符串中的匹配数?