问题
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));
回答1:
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)))));
来源:https://stackoverflow.com/questions/36374003/querying-array-of-strings-by-array-of-strings-in-elasticsearch-net