Elasticsearch conditional filter - elasticsearch

I need to filter out documents with some kind of conditional logic (I think), but I can't get this working.
My documents are like this:
{type: 'A'}
{type: 'B', foo: ['bar']}
{type: 'B', foo: []}
Now I need to filter out all documents of type 'B' where foo is empty.
In pseudocode the query would be:
if(type == 'B' && foo == []) {
// filter out this document
}
My main query looks like this:
query: {
filtered: {
query: {
bool: {
must: {
match_all: []
}
}
},
filter: {
bool:{
must_not: {
term: {'_hidden': true}
}
}
}
}
}
Elasticsearch Version is 1.5.0

If I understood, is that?
if type == a, all documents that have a will return.
And if type == b and the field foo is not there they will return, make sense?
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"should": [
{
"term": {
"type": "a"
}
},
{
"bool": {
"must": [
{
"term": {
"type": "b"
}
}
],
"must_not": [
{
"missing": {
"field": "foo"
}
}
]
}
}
]
}
}
}
}
}

Related

Elastic search query to filter documents based on the top value of nested array

The document has this structure:
{
innerArray: [
{set: "A", value: 123},
{set: "A", value: 234},
{set: "B", value: 115},
{set: "C", value: 133},
{set: "C", value: 256},
...
]
}
With a rather complex nested query, I can return documents where innerArray has elements both in set A and with value above a specified limit (e.g. 200). I can also order the inner_hits by value.
This query returns documents that have ANY inner_hits that match the criteria.
{
"query": {
"bool": {
"filter": [
{
"nested": {
"path": "innerArray",
"inner_hits": {
"sort": { "innerArray.value": { "order": "asc" } }
},
"query": {
"bool": {
"filter": [
{ "term": { "innerArray.set": "A" }},
{ "range": { "innerArray.value" : { "gt": 200 } } }
]
}
}
}
}
]
}
}
}
Now, I need only those where the FIRST inner_hit (filtered on 'set' and ordered by 'value') has a value above 200.
In pseudo SQL you could use a query with a HAVING clause but you could also write something like this:
select doc
from documents
where (
select min(value)
from doc.innerArray
where set = 'A'
) > 200
Is this feasible in elastic? How can I write such a query?
You would need to use Nested aggregation, a special single bucket aggregation that enables aggregating nested documents.
Query:
GET /_search
{
"query": {
"bool": {
"filter": [
{
"nested": {
"path": "innerArray",
"inner_hits": {
"sort": { "innerArray.value": { "order": "asc" } }
},
"query": {
"bool": {
"filter": [
{ "term": { "innerArray.set": "A" }},
{ "range": { "innerArray.value" : { "gt": 200 } } }
]
}
}
}
}
]
}
}
},
"aggs": {
"resellers": {
"nested": {
"path": "innerArray"
},
"aggs": {
"min_value": {
"min": {
"field": "innerArray.value"
}
}
}
}
}
}

Elasticsearch DSL bool query for filtration

I have an Elasticsearch DSL query as below
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"api": "A"
}
},
{
"match_phrase": {
"api": "B"
}
},
{
"match_phrase": {
"api": "C"
}
}
],
"minimum_should_match": 1
}
}
}
As I understand, this is something like
match if (api = A or api = B or api = C)
I want to add another condition checking a different field in the third check.
E.g match if (api = A or api = B or (api = C and another_field = D ) ) Any idea how to do this?
You can use a combination of bool/must query
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"api": "A"
}
},
{
"match_phrase": {
"api": "B"
}
},
{
"bool": {
"must": [
{
"match_phrase": {
"api": "C"
}
},
{
"match_phrase": {
"another_field": "D"
}
}
]
}
}
],
"minimum_should_match": 1
}
}
}

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" } }
]
}
}
}
}
]
}
}
}

How to combine more than two filters in elasticsearch?

I want to write query like this for elasticsearch 1.7:
SELECT * FROM prods WHERE
id=1 AND
name='flower' AND
(count_usd=1 OR prise_usd=5) AND
(count_eur=1 OR prise_eur=5)
?
I've read about nested bool ( https://www.elastic.co/guide/en/elasticsearch/guide/1.x/combining-filters.html ) but cannot apply it to my context :-(
You can nest a bool query within a bool query to achieve this kind of filtering:
{
"query": {
"filtered": {
"filter": {
"bool": {
"must": [{
"term": {"name":"flower"}
}],
"should": [{
"bool": {
"should": [{
"term": {
"count_usd": 1
}
}, {
"term": {
"prise_usd": 5
}
}]
}
}, {
"bool": {
"should": [{
"term": {
"count_eur": 1
}
}, {
"term": {
"prise_eur": 5
}
}]
}
}]
}
}
}
}
}
Note that should clause acts like an OR: at least one of the subclauses in a should must be true to match.

Filter documents where all values of an array meet some criteria in elasticsearch

I have documents that look like this:
{
times: [{start: "1461116454242"},{start:"1461116454242"}]
}
I want to get all documents where every start time is in the past. This query works when all times are in the future or all are in the past, but fails if only one time is in the future (still matches).
query: {
filtered: {
filter: {
bool: {
must: [
{
nested: {
path: "times",
filter: {
script : {
script: "doc['start'].value < now",
params: {
now: Date.now()
}
}
}
}
}
]
}
},
query: {
match_all: {}
}
}
}
One solution that I just realized:
query: {
filtered: {
filter: {
bool: {
must: [
{
nested: {
path: "times",
filter: {
"bool": {
"must": [
{
"range": {
"times.start": {
lt: new Date()
}
}
}
]
}
}
}
}
],
must_not: [
{
nested: {
path: "times",
filter: {
"bool": {
"must": [
{
"range": {
"times.start": {
gte: new Date()
}
}
}
]
}
}
}
}
]
}
},
query: {
match_all: {}
}
}
}
How about this one:
include_in_parent: true in your mapping:
"times": {
"type": "nested",
"include_in_parent": true,
"properties": {
"start": {
"type": "date"
}
}
}
and use the query_string syntax, without nested:
{
"query": {
"query": {
"query_string": {
"query": "times.start:<=now AND NOT times.start:>now"
}
}
}
}

Resources