Filter if condition is met


(wombat) #1

Hello fellow ES users,

I've just started looking into elasticsearch, so please point me to an
existing example if this has already been asked...

What i would like to be able to do is apply a query or filter - but only if
there is match, otherwise ignore it, a sort of "if" operation.

Here is an example, let's populate the index with two simple docs:

$ curl -XPUT localhost:9200/lucene/fun/1 -d '{
"field1": "abc",
"field2": "def",
"field3": {
"subfield1": "xyz"
}
}'

$ curl -XPUT localhost:9200/lucene/fun/2 -d '{
"field1": "abc",
"field2": "def",
"field3": {
"subfield1": "tuv"
}
}'

If we are certain we have valid, expected input, we can perform a simple
search:

$ curl -XPOST localhost:9200/lucene/fun/_search -d '{
"query": {
"bool": {
"must": [
{
"term": {
"field1": "abc"
}
},
{
"term": {
"field2": "def"
}
}
]
}
}
}'

That will return the two documents (as expected).

If i want to find just the first document then i can additionally specify
"field3":
$ curl -XPOST localhost:9200/lucene/fun/_search -d '{"query": {"bool":
{"must": [{"term": {"field1": "abc"}}, {"term": {"field2": "def"}}]}},
"filter": {"term": {"field3.subfield1": "xyz"}}}'

And that returns just the first document (again as expected).

The question is what query can i construct if i am given a potential value
for "field3.subfield1" but i don't know if its a valid value for the field.
So if it is found, then only return documents with that value for the
specified field, but if it isn't, then return all documents and ignore the
specified field.

Attempting to use "should" doesn't filter the results - for example the
following query returns both documents:
$ curl -XPOST localhost:9200/lucene/fun/_search -d '{"query": {"bool":
{"must": [{"term": {"field1": "abc"}}, {"term": {"field2": "def"}}],
"should": [{"term": {"field3.subfield1": "xyz"}}]}}}'

Thanks for any help.

--


(Clinton Gormley) #2

Hiya

The question is what query can i construct if i am given a potential
value for "field3.subfield1" but i don't know if its a valid value for
the field. So if it is found, then only return documents with that
value for the specified field, but if it isn't, then return all
documents and ignore the specified field.

You can't. A query is essentially a filter which is applied to each
individual document. It doesn't know about the other results.

So you either need to do two queries, or a single query which will
include the "field3" doc first, if it exists.

However, you can used NAMED filters to identify matching docs more
easily. For instance:

curl -XGET 'http://127.0.0.1:9200/iannounce_object/_search?pretty=1' -d
'
{
"query" : {
"custom_filters_score" : {
"query" : {
"text" : { "_all": "foobar"}
},
"filters" : [
{
"boost" : "10",
"filter" : {
"term" : {
"_name" : "xyz",
"field3.subfield1" : "xyz"
}
}
}
]
}
}
}
'

If there is a doc that has field3.subfield1 == 'xyz' then that doc will
appear first in the list, and matching results will include:

matched_filters: [ "xyz" ]

clint

--


(system) #3