私はC#でelasticsearch.netライブラリを使用しており、指定されたフィルターに一致するオブジェクトを照会しようとしています。
フィルターからの入力名の少なくとも 1 つがオブジェクトの 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ławomir Rosiekの回答から少しコードをアップグレードして、実際に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));