Elasticsearch multi date range aggregation using java api - elasticsearch

I use elasticsearch 2.2 and I want to do some aggregations like this:
{
"bool":{
"must":[
{
"query_string":{
"default_field":"berid",
"query":"F600-HHP1"
}
},
{
"query_string":{
"default_field":"matnr",
"query":"91P9289AAZZ"
}
}
]
},
"size":0,
"aggs":{
"count_by_date_range":{
"date_range":{
"field":"zzupload",
"ranges":[
{
"from":"2016-03-01",
"to":"2016-03-06"
},
{
"from":"2016-03-07",
"to":"2016-03-13"
},
{
"from":"2016-03-14",
"to":"2016-03-20"
},
{
"from":"2016-03-21",
"to":"2016-03-27"
},
{
"from":"2016-03-28",
"to":"2016-04-03"
},
{
"from":"2016-04-04",
"to":"2016-04-10"
},
{
"from":"2016-04-11",
"to":"2016-04-17"
},
{
"from":"2016-04-18",
"to":"2016-04-24"
},
{
"from":"2016-04-25",
"to":"2016-05-01"
},
{
"from":"2016-05-02",
"to":"2016-05-08"
},
{
"from":"2016-05-09",
"to":"2016-05-15"
},
{
"from":"2016-05-16",
"to":"2016-05-22"
},
{
"from":"2016-05-23",
"to":"2016-05-29"
},
{
"from":"2016-05-30",
"to":"2016-06-05"
},
{
"from":"2016-06-06",
"to":"2016-06-12"
},
{
"from":"2016-06-13",
"to":"2016-06-19"
}
]
},
"aggs":{
"total_fcst_qty":{
"sum":{
"field":"zzamqtu"
}
}
}
}
}
}
I need to calculate the sum of quantity on date range("from":"2016-03-01", "to":"2016-03-06", ...).But it's look like elasticsearch java api didn't support multi date_range.Here is my code:
SearchRequestBuilder searchBuilder = esClient.prepareSearch(Elasticsearch_sap_material_fcst_Index)
.setTypes(Elasticsearch_material_fcst_Type)
.setQuery(sb.toString())
.addAggregation(AggregationBuilders.dateRange("count_by_date_range").field("zzupload")
.addRange("2016-03-01", "2016-03-06")
.subAggregation(AggregationBuilders.sum("total_fcst_qty")));
How to calculate multiple date range using java api?
Thanks

You can just add multiple ranges like you did with the REST API:
SearchRequestBuilder searchBuilder = esClient.prepareSearch(Elasticsearch_sap_material_fcst_Index)
.setTypes(Elasticsearch_material_fcst_Type)
.setQuery(sb.toString())
.addAggregation(AggregationBuilders.dateRange("count_by_date_range").field("zzupload")
.addRange("2016-03-01", "2016-03-06")
.addRange("2016-05-23", "2016-05-29")
.subAggregation(AggregationBuilders.sum("total_fcst_qty")));
If you have a look at the source code, you can see that each call to addRange appends the new range to a list of ranges.

Related

Create different sub-aggregations depending on a top-level filters aggregation

I'm using a filters aggregation with ElasticSearch and within that aggregation I was wondering if I could create different sub-aggregations depending on the different filter buckets. In my case, I'm aggregating from two sources chrome and electron. For each source, I want to run different sub-aggregations. Below is my current aggregation hash:
aggs: {
**top_level_agg,
sources: {
filters: {
filters: {
chrome: { term: { source: TrackingEvent::CHROME_SOURCE } },
electron: { term: { source: TrackingEvent::ELECTRON_SOURCE } }
}
},
aggs: {
**chrome_specific_agg,
**electron_specific_agg
}
}
}
This works but isn't ideal because the chrome and electron filters aggs results both contain the chrome specific and electron specific aggs. It would be better if I could do something like this (I know this doesn't work):
aggs: {
**top_level_agg,
sources: {
filters: {
filters: {
chrome: {
term: { source: TrackingEvent::CHROME_SOURCE },
aggs: {
**chrome_specific_agg
}
},
electron: {
term: { source: TrackingEvent::ELECTRON_SOURCE },
aggs: {
**electron_specific_agg
}
}
}
}
}
}
I'm not sure if this is possible with ES but I thought I'd ask. Any ideas on how to make this work?
Sure you can. Just gotta adjust the nested-ness a bit:
{
"aggs": {
"top_level_agg": {},
"chrome_specific_agg_name": {
"filter": {
"term": {
"source": "TrackingEvent::CHROME_SOURCE"
}
},
"aggs": {
"chrome_specific_agg": {}
},
"electron_specific_agg_name": {
"filter": {
"term": {
"source": "TrackingEvent::ELECTRON_SOURCE"
}
},
"aggs": {
"electron_specific_agg": {}
}
}
}
}

Hello, I am trying to use wildcard query with filters in elastric search in my node js application

I am getting search item from user as
let eventSearch="*"+event.SearchTerm+"*";
This is the query object
let queryObject =
{
index: 'mark_deling_test2',
type: 'product',
body: {
"from" : event.StartIndex, "size" : event.ResultSize,
"query": {
"filtered":{
"query":{
"query_string":{
"fields": [ "Name^2.5", "Description", "keywords^1.75" ],
"query":eventSearch,
"analyze_wildcard":true
}
},
"filter":{
"term":{
"groups": "CA-IBO"
}
}
}
}
}
};
Then sending this query object for searching
This is not working. If I don't use the filter it works.
Please Help!
Get mark_deling_test2/_search
{
“query”: {
“bool”: {
“must”: {
“query_string”: {
“query”: “nut*“,
“fields”: [“Name”, “Description”, “keywords”]
}
},
“filter”: {
“term”: {
“groups”: “US-IBO”
}
}
}
}
}

Elasticsearch boost with Wildcardsearch on _all

Im trying to search documents with wildcard and _all. But It does not seem like it's possible to get boosted result with wildcard on _all ?
MappingRequest:
"theboostingclass": {
"properties": {
"Important": {
"boost": 2.0,
"type": "string"
},
"LessImportant": {
"type": "string"
},
"Garbage": {
"type": "string"
}
}
}
}
Indexing:
{
"index" :
{
"_index":"boosting",
"_type":"theboostingclass"
}
}
{
"Important":"bomb",
"LessImportant":"kruka",
"Garbage":"kalkon"
}
{
"index" :
{
"_index":"boosting",
"_type":"theboostingclass"
}
}
{
"Important":"kalkon",
"LessImportant":"bomb",
"Garbage":"bomber"
}
{
"index" :
{
"_index":"boosting",
"_type":"theboostingclass"
}
}
{
"Important":"kruka",
"LessImportant":"bomber",
"Garbage":"bomb"
}
Query
"query": {
"wildcard": {
"_all": {
"value": "*bomb*"
}
}
}
The result returs all hits with a Score of 1 and a seemingly random order. Which is not really what Im after. I want the hit on "Important"field to yield a higher score.
If I do a wildcard search on all 3 fields the scoring seems correct. However I want to use it on _all. Any ideas?
Please see documentation here:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-term-rewrite.html. Note that the reason it works with a constant scoring by default is for performance.
I believe you need to modify your query as follows:
"query": {
"wildcard": {
"_all": {
"value": "*bomb*",
"rewrite": "scoring_boolean"
}
}
}

How to filter terms aggregation

Currently I have something like this
aggs: {
categories: {
terms: {
field: 'category'
}
}
}
and this is giving me number of products in each category. But I have additional condition. I need to get number of products in each category which are not sold already, so I need to perform filter on terms somehow.
Is there some elegant way of doing this using aggregation framework, or I need to write filtered query?
Thank you
You can merge between Terms Aggregation and Filter Aggregation, and this is how it should look: (tested)
aggs: {
categories: {
filter: {term: {sold: true}},
aggs: {
names: {
terms: {field: 'category'}
}
}
}
}
You can add also more conditions to the filter, I hope this helps.
Just to add to the other answer, you can also use a nested query. This is similar to what I had to do. I'm using Elasticsearch 5.2.
From the docs, here is the basic syntax:
"aggregations" : {
"<aggregation_name>" : {
"<aggregation_type>" : {
<aggregation_body>
}
[,"aggregations" : { [<sub_aggregation>]+ } ]?
}
[,"<aggregation_name_2>" : { ... } ]*
}
This is how I implemented it:
GET <path> core_data/_search
{
"aggs": {
"NAME": {
"nested": {
"path": "ATTRIBUTES"
},
"aggs": {
"NAME": {
"filter": {
"term": {
"ATTRIBUTES.ATTR_TYPE": "EDUCATION_DEGREE"
}
},
"aggs": {
"NAME": {
"terms": {
"field": "ATTRIBUTES.DESCRIPTION",
"size": 100
}
}
}
}
}
}
}
}
This filtered the data down to one bucket, which is what I needed.

Mixed filters, using OR as well as AND, in ElasticSearch

In your opinion what would be the best way to do the following?
I want to filter an ElasticSearch query by several ranges that are grouped in an OR filter, and then by one final range that needs to be included as an AND filter. The explanation is a bit crappy but hopefully the pseudo-code below will help...
Basically I tried structuring the following query:
{
"query":{
"multi_match":{
"query":"blue",
"fields":[
"name"
]
}
},
"sort":{
"_score":{
"order":"desc",
"missing":"_last"
}
},
"from":"0",
"size":"24",
"facets":{
"rating":{
"range":{
"field":"rating",
"ranges":[
{
"from":1
},
{
"from":2
},
{
"from":3
},
{
"from":4
}
]
}
},
"price":{
"range":{
"field":"price",
"ranges":[
{
"to":10
},
{
"from":10,
"to":100
},
{
"from":100,
"to":1000
}
{
"from":1000
}
]
}
}
},
"filter":{
"or":[
{
"range":{
"price":{
"from":"10",
"to":"100"
}
}
},
{
"range":{
"price":{
"from":"100",
"to":"1000"
}
}
}
],
"and":{
"numeric_range":{
"rating":{
"gte":"4"
}
}
}
}
}
This failed with the error that there was "No parser for element [numeric_range]". So I tried replacing:
"and":{
"numeric_range":{
"rating":{
"gte":"4"
}
}
}
with:
"numeric_range":{
"rating":{
"gte":"4"
}
}
The query now returns results but it's returning results with prices in the ranges 10-100, 100-1000 and ANY results with a rating greater than 4 (even if their price is outside of the defined range).
Any clues on how I could do this query? Do I need to be using a bool filter?
Ah ha, figured it out, with the help of Boaz Leskes over on the ElasticSearch mailing list!
It should be structured like this:
filter: {
bool: {
must: [
{
"numeric_range":{
"rating":{
"gte":"4"
}
}
}
],
should: [
{
"range":{
"price":{
"from":"10",
"to":"100"
}
}
},
{
"range":{
"price":{
"from":"100",
"to":"1000"
}
}
}
]
}
}

Resources