Reputation: 65
I have built an application in C# which searches my Elasticsearch documents and this all works fine using this code....
List<AuditLog> resultsList = Client.SearchAsync<AuditLog>(s => s
.From(0)
.Take(noRows)
.Query(q => q
.Bool(b => b
.Must(mu => mu.MatchPhrase(mp => mp.Field("audit_Event").Query(auditEvents)),
mu => mu.Match(ma => ma.Field(field).Query(value))
)
)
)).Result.Documents.ToList();
This all works fine but there is a new requirement to search the audit_Event field against multiple phrases, such as "User Login", "Add Employee" etc
I have found reference to multi_match but this appears to be more related to searching across multiple fields rather than multiple values in one field.
Following discussions below, TermQuery would seem to do the job but doesn't return any values. Any ideas?
QueryContainer queryAnd = new TermQuery() { Field = "audit_Application", Value = "MyApplication" };
QueryContainer queryOr = new TermQuery() { Field = "audit_Event", Value = "Employee Inserted" };
queryOr |= new TermQuery() { Field = "audit_Event", Value = "Employee Updated" };
QueryContainer queryMain = queryAnd & queryOr;
resultsList = Client.SearchAsync<AuditLog>(s => s
.From(0)
.Take(noRows)
.Query(q => q
.Bool(b => b
.Must(queryMain)
)
)).Result.Documents.ToList();
I've also checked the two queries using Kibana, the first one returns data but the second one doesn't, and am now wondering if it a problem with how the data is indexed....
GET auditlog/_search
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"audit_Event": "Employee Updated"
}
},
{
"match_phrase": {
"audit_Event": "Employee Inserted"
}
}
]
}
}
}
GET auditlog/_search
{
"query" : {
"terms": {
"audit_Event": ["Employee Updated","Employee Inserted"]
}
}
}
Upvotes: 2
Views: 2326
Reputation: 1394
Based on your statement that the OR
query works as expected, below is a way you can build the query using NEST
. You may make any specific modifications as needed.
This snippet of code is responsible for triggering the search call
var searchDescriptor = new SearchDescriptor<AuditLog>()
.Query(q => Blah(auditEventsList))
.From(0)
.Take(noRows);
// other methods you want to chain here
var response = Client.searchAsync<AuditLog>(searchDescriptor);
The search query is generated here. Notice the use of SHOULD
and the call to another method that is responsible for dynamically generating the match_phrase
queries.
private static QueryContainer Blah(List<string> auditEventsList)
{
return new QueryContainerDescriptor<AuditLog>().Bool(
b => b.Should(
InnerBlah(auditEventsList)
)
);
}
This method generates an array of match_phrase
queries that are passed to should
in the above snippet. These are generated by iterating over all the audit events that are received.
private static QueryContainer[] InnerBlah(List<string> auditEventsList)
{
QueryContainer orQuery = null;
List<QueryContainer> queryContainerList = new List<QueryContainer>();
foreach(var item in auditEventsList)
{
orQuery = new MatchPhraseQuery { Field = "audit_Event", Query = item };
queryContainerList.Add(orQuery);
}
return queryContainerList.ToArray();
}
Upvotes: 1
Reputation: 642
Please try this:
QueryContainer queryOr = new MatchPhraseQuery() { Field = "audit_Event", Query = "Employee Inserted" };
queryOr |= new MatchPhraseQuery() { Field = "audit_Event", Query = "Employee Updated" };
ISearchResponse<AuditLog> resultAuditLog = Client.Search<AuditLog>(s => s
.RequestConfiguration(r => r.DisableDirectStreaming())
.From(0)
.Size(100)
.Query(q2 => q2
.Bool(b => b
.Should(queryOr))
)
);
Upvotes: 0
Reputation: 16172
If you want to match multiple phrases against a single field, then you can use the following combinations of bool query with match_phrase
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"audit_Event": "User Login"
}
},
{
"match_phrase": {
"audit_Event": "Add Employee"
}
}
]
}
}
}
Upvotes: 0