ElasticSearch query filter on nested documents - elasticsearch

I need to filter my index based on a nested property :
myNestedProperty: [
{ id: 1, displayName: toto },
{ id: 2, displayName: tata },
{ id: 3, displayName: titi }
]
myNestedProperty: [
{ id: 4, displayName: dodo },
{ id: 5, displayName: dada },
{ id: 6, displayName: didi }
]
I would like to count how many have a Toto and how many does not. I try with the following query :
"aggs": {
"HasToto": {
"filter": {
"nested": {
"path": "myNestedProperty",
"query": {
"match": {
"myNestedProperty.id": "1"
}
}
}
}
},
"NoToto": {
"filter": {
"nested": {
"path": "myNestedProperty",
"query": {
"bool": {
"must_not": [
{"match": {
"myNestedProperty.id": "1"
}}
]
}
}
}
}
}
}
The "HasToto" seems to return the expected result but it's not the case of "NoToto" filter (Too much data returned).
Rules :
"Toto" can only be there once in myNestedProperty. If I have "Toto", I can't have "Dodo" or another one.
It's a hierarchical object :
-- Toto
---- Tata
------- Titi
I simplify the data due to their complexity, I hope it's enough clear with this simple object.
How to achieve this please ? Thanks in advance.

I found the solution \o/
"aggs": {
"HasToto": {
"filter": {
"bool": {
"must": {
"nested": {
"path": "myNestedProperty",
"query": {
"match": {
"myNestedProperty.id": "1"
}
}
}
}
}}
},
"NoToto": {
"filter": {
"bool": {
"must_not": [
{
"nested": {
"path": "myNestedProperty",
"query": {
"match": {
"myNestedProperty.id": "1"
}
}
}
}
]
}
}
}
}

Related

Replace OR filtered query in elasticsearch while upgrading to elastic-search 5

I am trying to upgrade elastic-search to version 5. Previously I was using elastic-search version 2. I am having hard time converting OR query to bool[:should] query. Here is how my query looks like that was working in ES-2.
query: {:bool=>{
:should=>[
{:term=>{:user=>{:term=>70890}}},
{:term=>{:assignee=>{:term=>70890}}},
{:term=>{:participant=>{:term=>70890}}}],
:minimum_number_should_match=>1,
:filter=>[{:bool=> {:must_not=>{:exists=>{:field=>:date}}}},
{:term=>{:deleted=>false}},
{:or=>{:filters=>[
{:term=>{:user=>70890}},
{:term=>{:assignee=>70890}},
{:term=>{:private=>false}}
]}
}
]
}}
Query:
{
"bool": {
"should": [
{
"term": {
"user": {
"term": 70890
}
},
{
"term": {
"assignee": {
"term": 70890
}
}
},
{
"term": {
"participant": {
"term": 70890
}
}
}
],
"minimum_number_should_match": 1,
"filter": [
{
"bool": {
"must_not": {
"exists": {
"field": "date"
}
}
}
},
{
"term": {
"deleted": false
}
},
{
"or": {
"filters": [
{
"term": {
"user": 70890
}
},
{
"term": {
"assignee": 70890
}
},
{
"term": {
"private": false
}
}
]
}
}
]
}
}
I want to replace {:or=>{:filters}}. I have tried moving this part in :bool[:should] query but it gives wrong results.
q[:bool][:should] << {term: {user: 70890}}
q[:bool][:should] << {term: {assignee: 70890}}
q[:bool][:should] << {term: {private: false}}
q[:bool][:minimum_should_match] = 1
When I change minimum_should_match=2 it changes results. How do I fix it?

How to search for separate key and value fields in an array in ElasticSearch?

My ElasticSearch documents contain a nested collection of form fields. Each field has a name and a value and the mapping is as follows:
form: {
properties: {
id: { type: 'integer' },
name: { type: 'text' },
form_data: {
type: 'nested',
properties: {
'name': { type: 'keyword' },
'value': { type: 'text', analyzer: 'full_text_analyzer' }
}
}
}
}
I need to allow the user to search for multiple form fields to refine their search. They can choose which fields to search by and assign a value to each. For example
applicant_name = 'Joe'
pet_type = 'dog'
This would find all documents that contained a field named applicant_name which had a value fuzzy matching Joe as well as a field named pet_type and a value fuzzy matching dog.
The query I'm trying to do this with is as follows.:
{
"query": {
"bool": {
"must": [{
"nested": {
"path": "form_data",
"query": {
"filter": {
"bool": {
"must": [
{
"bool": {
"must": [
{ "term": { "form_data.name": "applicant_name" } },
{ "match": { "form_data.value": "Joe" } }
]
}
},
{
"bool": {
"must": [
{ "term": { "form_data.name": "pet_type" } },
{ "match": { "form_data.value": "dog" } }
]
}
}
]
}
}
}
}
}]
}
}
}
However, I get 0 results.
Try using a nested query per condition in your initial "must" clause:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "form_data",
"query": {
"bool": {
"must": [
{ "term": { "form_data.name": "applicant_name" } },
{ "match": { "form_data.value": "Joe" } }
]
}
}
}
},
{
"nested": {
"path": "form_data",
"query": {
"bool": {
"must": [
{ "term": { "form_data.name": "pet_type" } },
{ "match": { "form_data.value": "dog" } }
]
}
}
}
}
]
}
}
}

Match multiple properties on the same nested document in ElasticSearch

I'm trying to accomplish what boils down to a boolean AND on nested documents in ElasticSearch. Let's say I have the following two documents.
{
"id": 1,
"secondLevels": [
{
"thirdLevels": [
{
"isActive": true,
"user": "anotheruser#domain.com"
}
]
},
{
"thirdLevels": [
{
"isActive": false,
"user": "user#domain.com"
}
]
}
]
}
{
"id": 2,
"secondLevels": [
{
"thirdLevels": [
{
"isActive": true,
"user": "user#domain.com"
}
]
}
]
}
In this case, I want to only match documents (in this case ID: 2) that have a nested document with both isActive: true AND user: user#domain.com.
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "secondLevels.thirdLevels",
"query": {
"bool": {
"must": [
{
"term": {
"secondLevels.thirdLevels.isActive": true
}
},
{
"term": {
"secondLevels.thirdLevels.user": "user#domain.com"
}
}
]
}
}
}
}
]
}
}
}
However, what seems to be happening is that my query turns up both documents because the first document has one thirdLevel that has isActive: true and another thirdLevel that has the appropriate user.
Is there any way to enforce this strictly at query/filter time or do I have to do this in a script?
With nested-objects and nested-query, you have made most of the way.
All you have to do now is to add the inner hits flag and also use source filtering for move entire secondLevels documents out of the way:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "secondLevels.thirdLevels",
"query": {
"bool": {
"must": [
{
"term": {
"secondLevels.thirdLevels.isActive": true
}
},
{
"term": {
"secondLevels.thirdLevels.user": "user#domain.com"
}
}
]
}
},
"inner_hits": {
"size": 100
}
}
}
]
}
}
}

How to combine multiple bool queries in elasticsearch

I want to create the equivalent of the following query -
(city = 'New York' AND state = 'NY') AND ((businessName='Java' and businessName='Shop') OR (category='Java' and category = 'Shop'))
I tried different combinations of bool queries using must and should but nothing seems to be working. Can this be done?
How about something like this:
{
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"term": {
"city": "New york"
}
},
{
"term": {
"state": "NY"
}
},
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"term": {
"businessName": "Java"
}
},
{
"term": {
"businessName": "Shop"
}
}
]
}
},
{
"bool": {
"must": [
{
"term": {
"category": "Java"
}
},
{
"term": {
"category": "Shop"
}
}
]
}
}
]
}
}
]
}
}
}

ElasticSearch ignoring sort when filtered

ElasticSearch Version: 0.90.1, JVM: 1.6.0_51(20.51-b01-457)
I'm trying to do two things with my ElasticSearch query: 1) filter the results based on a boolean (searchable) and "open_date < tomorrow" and 2) two sort by the field "open_date" DESC
This produces the following query:
{
"query": {
"bool": {
"should": [
{
"prefix": {
"name": "foobar"
}
},
{
"query_string": {
"query": "foobar"
}
},
{
"match": {
"name": {
"query": "foobar"
}
}
}
],
"minimum_number_should_match": 1
},
"filtered": {
"filter": {
"and": [
{
"term": {
"searchable": true
}
},
{
"range": {
"open_date": {
"lt": "2013-07-16"
}
}
}
]
}
}
},
"sort": [
{
"open_date": "desc"
}
]
}
However, the results that come back are not being sorted by "open_date". If I remove the filter:
{
"query": {
"bool": {
"should": [
{
"prefix": {
"name": "foobar"
}
},
{
"query_string": {
"query": "foobar"
}
},
{
"match": {
"name": {
"query": "foobar"
}
}
}
],
"minimum_number_should_match": 1
}
},
"sort": [
{
"open_date": "desc"
}
]
}
... the results come back as expected.
Any ideas?
I'm not sure about the Tire code, but the JSON does not correctly construct a filtered query. My guess is that this overflows and causes the sort element to also not be correctly parsed.
A filtered query should be constructed like this (see http://www.elasticsearch.org/guide/reference/query-dsl/filtered-query/ ):
{
"query": {
"filtered": { // Note: this contains both query and filter
"query": {
"bool": {
"should": [
{
"prefix": {
"name": "foobar"
}
},
{
"query_string": {
"query": "foobar"
}
},
{
"match": {
"name": {
"query": "foobar"
}
}
}
],
"minimum_number_should_match": 1
}
},
"filter": {
"and": [
{
"term": {
"searchable": true
}
},
{
"range": {
"open_date": {
"lt": "2013-07-16"
}
}
}
]
}
}
},
"sort": [
{
"open_date": "desc"
}
]
}
Cheers,
Boaz

Resources