Elasticsearch - Term null? - elasticsearch

I'm having trouble matching null terms in NEST.
I'm trying to get some details via a query.
It works ok, but one thing I can't understand -
For some reason I can't do a term that equals to null value.
What am I doing wrong?
My Code:
result = _mainManager.Client.Search<object>
(q => q
.Type("Mail")
.Query(c =>
c.Term("SentMail_Sender_Id", userId) &&
c.Term("SentMail_EmbedAccountId", null) &&
!c.Term("SentMail_Status", Status.REMOVED.ToString().ToLower()) &&
c.Range(v => v.OnField("SentMail_Upload_Files_Count").Greater(0)))
.Size(int.MaxValue)
.Sort(s => s.OnField("SentMail_Creation_Date").Descending()));
It works ok, no null term is found in my result Json:
{
"size": 2147483647,
"sort": [
{
"SentMail_Creation_Date": {
"order": "desc"
}
}
],
"query": {
"bool": {
"must": [
{
"term": {
"SentMail_Sender_Id": {
"value": 7186
}
}
},
{
"range": {
"SentMail_Upload_Files_Count": {
"gt": "0"
}
}
}
],
"must_not": [
{
"term": {
"SentMail_Status": {
"value": "removed"
}
}
}
]
}
}
}

Found it!
result = _mainManager.Client.Search<object>
(q => q
.Type("Mail")
.Query(c =>
c.Term("SentMail_Sender_Id", userId) &&
!c.Term("SentMail_Status", Status.REMOVED.ToString().ToLower()) &&
c.Range(v => v.OnField("SentMail_Upload_Files_Count").Greater(0)))
.Filter(f => f.Missing("SentMail_EmbedAccountId"))
.Size(int.MaxValue)
.Sort(s => s.OnField("SentMail_Creation_Date").Descending()));

Related

Converting JSON to Elastic NEST query doesn't work as intended

I'm trying to convert the following JSON to NEST, but it's not working as intended. It does match the field with the website, but it doesn't match the range, so I get some very old results.
When using Kibana to search, I send this request:
"query": {
"bool": {
"must": [],
"filter": [
{
"bool": {
"should": [
{
"match": {
"domain": "website.com"
}
}
],
"minimum_should_match": 1
}
},
{
"range": {
"#timestamp": {
"gte": "2020-08-03T12:37:07.821Z",
"lte": "2020-08-18T12:37:07.821Z",
"format": "strict_date_optional_time"
}
}
}
],
"should": [],
"must_not": []
}
},
And converted to NEST:
SearchDescriptor<ApacheRequest> Query(SearchDescriptor<ApacheRequest> qc)
{
var query = qc.Query(q =>
q.Bool(b =>
b.Filter(f =>
f.Bool(fb =>
fb.Should(sh =>
sh.Match(ma => ma
.Field(x => x.Domain)
.Query("website.com")
)
)
),
f => f.Range(r => r.GreaterThanOrEquals(timestamp))
)
)
);
return query;
}
As I said, it matches the domain, but not the range. I get results a month back, even though I've tested that my timestamp is correct.
What am I doing wrong?
Ah, I found the issue.. I'm not supposed to use .Range() but rather .DateRange(). Now my query looks like this:
SearchDescriptor<ApacheRequest> Query(SearchDescriptor<ApacheRequest> qc)
{
var query = qc.Query(q =>
q.Bool(b =>
b.Filter(f =>
f.Bool(fb =>
fb.Must(sh =>
sh.Match(ma => ma
.Field(x => x.Domain)
.Query("website.com")
)
)
),
f => f.DateRange(r =>
r.Field(fi => fi.Timestamp).GreaterThanOrEquals(from)
)
)
)
);
return query;
}

Elastic search recreating query in NEST not working

Im trying to recreate query in from Kibana dev into NEST but it's not giving me the same results.
The query I run in Kibana works perfectly returning 1 result
Here is my Kibana query:
GET /cats/_doc/_search
{
"query":{
"bool" : {
"minimum_should_match" :3,
"should": [
{"term" : { "name" : "cats" }},
{"term" : { "name" : "are" }},
{"term" : { "name" : "craze" }}
]
}
}
}
When I create the query in NEST it returns no results except when I change the minimum_should_match to 1 (it then returns 2 results )
Here is my NEST query:
string[] tmp = "Cats are craze".ToLower().Split(new string[] { " " }, StringSplitOptions.None);
var cats = ElasticMain.Search<dynamic>(s => s.From(from).Size(20).Query(
q => q.Bool(
b => b.MinimumShouldMatch(tmp.Length).Should(
l => l.Terms(
t => t.Name("name").Field("name").Terms(tmp)))
)));
What am I doing wrong?
You are not building the same query in NEST as you have in Kibana; the former is using a terms query, whilst the latter is using three term queries in a bool query should clause. The semantics of these two queries in combination with minimum should match is different.
The same query in NEST is
var client = new ElasticClient();
string[] tmp = "Cats are craze".ToLower().Split(new string[] { " " }, StringSplitOptions.None);
var from = 0;
var searchResponse = client.Search<dynamic>(s => s
.From(from)
.Size(20)
.Query(q => q
.Bool(b =>
{
b.MinimumShouldMatch(tmp.Length);
var shouldQueries =
new List<Func<QueryContainerDescriptor<dynamic>, QueryContainer>>(tmp.Length);
for (var i = 0; i < tmp.Length; i++)
{
var value = tmp[i];
shouldQueries.Add(qc => qc.Term(t => t
.Field("name")
.Value(value)
));
}
b.Should(shouldQueries);
return b;
})
)
);
which builds the following query
{
"from": 0,
"query": {
"bool": {
"minimum_should_match": 3,
"should": [
{
"term": {
"name": {
"value": "cats"
}
}
},
{
"term": {
"name": {
"value": "are"
}
}
},
{
"term": {
"name": {
"value": "craze"
}
}
}
]
}
},
"size": 20
}
When the number of should clauses that must match is equal to minimum_should_match as in this example, it's effectively the same as saying that they are all must clauses (without the minimum_should_match)
var client = new ElasticClient();
string[] tmp = "Cats are craze".ToLower().Split(new string[] { " " }, StringSplitOptions.None);
var from = 0;
var searchResponse = client.Search<dynamic>(s => s
.From(from)
.Size(20)
.Query(q =>
tmp.Aggregate((QueryContainer)null, (qc, v) => qc && q.Term("name", v))
)
);
which takes advantage of operator overloading on NEST queries to && them together, to build the query
{
"from": 0,
"query": {
"bool": {
"must": [
{
"term": {
"name": {
"value": "cats"
}
}
},
{
"term": {
"name": {
"value": "are"
}
}
},
{
"term": {
"name": {
"value": "craze"
}
}
}
]
}
},
"size": 20
}

Elastic Search Query For Making Range For 2 Mappings

Hi i want make query that x greater than min_rent and x least than max_rent.
Here the mappings.
'mappings' => [
'project_listing_v1' => [
'properties' => [
'location' => [
'type' => 'geo_point'
],
'min_rent'=>[
'type'=>'short',
],
'max_rent'=>[
'type'=>'short',
]
]
You can use a bool query with a must clause as such:
GET project_listing_v1/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"min_rent": {
"gt": x
}
}
},
{
"range": {
"max_rent": {
"lt": x
}
}
}
]
}
}
}
Note: You have to replace 'x' in the query with the actual value.
More on bool queries: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

how to use two parallel Aggregation for elasticsearch nest

Like bellow http request:
base on TERM "service_project" aggr, there are 2 another SUM aggr "service_hour_price" and "servic_part_price". Can I use Elasticsearch Nest do the same thing?
"aggs": {
"3": {
"terms": {
"field": "service_project",
"size": 50,
"order": {
"1": "desc"
}
},
"aggs": {
"1": {
"sum": {
"field": "service_hour_price"
}
},
"2": {
"sum": {
"field": "servic_part_price"
}
}
}
}
}
Now I can use only one SUM Aggr base on That Term Aggr, like this:
return s.Aggregations(a => a
.Terms("names", st => st
.Field(o => o.service_project)
.OrderDescending("sum")
.Size(term_count)
.Aggregations(aa => aa
.Sum("sum", m => m
.Field(o => o.service_hour_price)))));
You are almost there:
s.Aggregations(a => a
.Terms("3", t => t
.Field("service_project")
.Size(50)
.OrderDescending("1")
.Aggregations(aa => aa
.Sum("1", sum => sum.Field("service_hour_price"))
.Sum("2", sum => sum.Field("service_part_price")))
));
Hope it helps.

ElasticSearch .NET Nest Sub Aggregation

Consider the following aggregation and sub aggregation:
.Aggregations(a => a
.Terms("ByCustomerByImpressionCount", tad => tad
.Field(o => o.CustomerName)
.OrderDescending("sumImpressionCount")
.Aggregations(ad => ad
.Sum("sumImpressionCount", sad => sad
.Field(o => o.ImpressionCount)
)
)
))
The query works fine, and I get results.
I can access the top aggregation with:
var agg = results.Aggs.Terms("ByCustomerByImpressionCount");
According to the docs, I should be able to get the sub agg with:
var subAgg = agg.Aggs.Sum("sumImpressionCount");
But Aggs isn't even a property of agg - any ideas?
EDIT:
This is the only way I've been able to get to the sub aggregation:
PopulateList(results.Aggs.Terms("CustomersByImpressionCount").Items, CustomersByImpressionCount);
private void PopulateList(IList<KeyItem> items, List<DataContainer> listToPopulate)
{
items.ForEach(item =>
{
listToPopulate
.Add(new DataContainer() { Name = item.Key, Sum = ((ValueMetric)item.Aggregations.First().Value).Value });
});
}
...but this seems to be overly complicated. Here is the ES query:
"query": {
"bool": {
"must": [
{ "range": { "requestedShipDate": {
"gte": "2014-11-26",
"lte": "2015-02-03"
} }
}
],
"must_not": [
{"terms": {
"status": [
"Order Shipped",
"Canceled",
"Completed"
]
}}
]
}
},
"aggs": {
"ByCustomerByImpressionCount": {
"terms": {
"field": "customerName",
"order": { "sumImpressionCount": "desc" }
},
"aggs": {
"sumImpressionCount": { "sum": { "field": "impressionCount" }}
}
}}
And here is partial response:
"ByCustomerByImpressionCount": {
"doc_count_error_upper_bound": -1,
"sum_other_doc_count": 26785,
"buckets": [
{
"key": "<One of our customers>",
"doc_count": 1722,
"sumImpressionCount": {
"value": 9583176
}
}
The documentation is wrong. We'll fix that ASAP.
Here is the correct way to access your aggregations:
var terms = results.Aggs.Terms("ByCustomerByImpressionCount");
foreach(var term in terms.Items)
{
var sum = term.Sum("sumImpressionCount");
}

Resources