exact match query in elasticsearch - elasticsearch

I'm trying to run an exact match query in ES
in MYSQL my query would be:
SELECT * WHERE `content_state`='active' AND `author`='bob' AND `title` != 'Beer';
I looked at the ES docs here:
https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_exact_values.html
and came up with this:
{
"from" : '.$offset.', "size" : '.$limit.',
"filter": {
"and": [
{
"and": [
{
"term": {
"content_state": "active"
}
},
{
"term": {
"author": "bob"
}
},
{
"not": {
"filter": {
"term": {
"title": "Beer"
}
}
}
}
]
}
]
}
}
but my results are still coming back with the title = Beer, it doesn't seem to be excluding the titles that = Beer.
did I do something wrong?
I'm pretty new to ES

I figured it out, I used this instead...
{
"from" : '.$offset.', "size" : '.$limit.',
"query": {
"bool": {
"must": [
{
"query_string": {
"default_field": "content_state",
"query": "active"
}
},
{
"query_string": {
"default_field": "author",
"query": "bob"
}
}
],
"must_not": [
{
"query_string": {
"default_field": "title",
"query": "Beer"
}
}
]
}
}
}

Query String Query is a pretty good concept to handle various relationship between search criteria. Have a quick look into Query string query syntax to understand in detail about this concept
{
"query": {
"query_string": {
"query": "(content_state:active AND author:bob) AND NOT (title:Beer)"
}
}
}

Filters are supposed to work on exact values, if you had defined your mapping in a manner where title was a non-analyzed field, your previous attempt ( with filters) would have worked as well.
{
"mappings": {
"test": {
"_all": {
"enabled": false
},
"properties": {
"content_state": {
"type": "string"
},
"author": {
"type": "string"
},
"title": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
}

Related

Can you reference other queries in Elasticsearch percolator?

can percolator queries reference other stored query docs in a percolator index? For example, given I have the following Boolean query, with _id=1, already indexed in the percolator:
{
"query": {
"bool": {
"must": [
{ "term": { "tag": "wow" } }
]
}
}
}
Could I have another query, with _id=2, indexed (note that I'm making up the _percolator_ref_id terms query key):
{
"query": {
"bool": {
"should": [
{ "term": { "tag": "elasticsearch" } },
{ "terms" : { "_percolator_ref_id": [1] } }
]
}
}
}
If I percolated the following document:
{ "tag": "wow" }
I would expect both _id=1 and _id=2 queries to match. Does some functionality like _percolator_ref_id exist?
Thanks!
Edit: To clarify, I do not know beforehand how many query references appear in a given query (e.g., the _id=2 query could reference 10 other queries potentially).
You can do something like below
2 queries are registered in below index
PUT myindex
{
"mappings": {
"properties": {
"query1": {
"type": "percolator"
},
"query": {
"type": "percolator"
},
"field": {
"type": "text"
}
}
}
}
You can use bool and must/should to combine different queries
GET /myindex/_search
{
"query": {
"bool": {
"must": [
{
"percolate": {
"field": "query",
"document": {
"field": "fox jumps over the lazy dog"
}
}
},
{
"percolate": {
"field": "query1",
"document": {
"field": "fox jumps over the lazy dog"
}
}
}
]
}
}
}

Elastic Search query for an AND condition on two properties of a nested object

I have the post_filter as below, Where I am trying to filter records where the school name is HILL SCHOOL AND containing a nested child object with name JOY AND section A.
school is present in the parent object, Which is holding children list of nested objects.
All of the above are AND conditions.
But the query doesn't seem to work. Any idea why ? And is there a way to combine the two nested queries?
GET /test_school/_search
{
"query": {
"match_all": {}
},
"post_filter": {
"bool": {
"must_not": [
{
"bool": {
"must": [
{
"term": {
"schoolname": {
"value": "HILL SCHOOL"
}
}
},
{
"nested": {
"path": "children",
"query": {
"bool": {
"must": [
{
"match": {
"name": "JACK"
}
}
]
}
}
}
},
{
"term": {
"children.section": {
"value": "A"
}
}
}
]
}
}
]
}
}
}
The schema is as below:
PUT /test_school
{
"mappings": {
"_doc": {
"properties": {
"schoolname": {
"type": "keyword"
},
"children": {
"type": "nested",
"properties": {
"name": {
"type": "keyword",
"index": true
},
"section": {
"type": "keyword",
"index": true
}
}
}
}
}
}
}
Sample data as below:
POST /test_school/_doc
{
"schoolname":"HILL SCHOOL",
"children":{
"name":"JOY",
"section":"A"
}
}
second record
POST /test_school/_doc
{
"schoolname":"HILL SCHOOL",
"children":{
"name":"JACK",
"section":"B"
}
}
https://stackoverflow.com/a/17543151/183217 suggests special mapping is needed to work with nested objects. You appear to be falling foul of the "cross object matching" problem.

Searching in specific fields of types

Consider the following query:
{
"query" : {
"match_phrase" : {
"_all" : "Smith"
}
}
}
How would I specify in which fields of which types it may search, instead of searching in everything? (field names may be non-unique across types)
I've tried the query below, but it didn't work (it doesn't return results, it does when I remove person. from all fields):
{
"query": {
"multi_match": {
"query": "Smith",
"fields": [
"person.first_name",
"person.last_name",
"person.age"
],
"lenient": true
}
}
}
I'm sending these queries to http://localhost:9200/tsf-model/_search.
If you can build your query dynamically, I think you can use a combination of your multi_match query and a type query for each type, in order to achieve what you want:
{
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"bool": {
"filter": [
{
"type": {
"value": "type1"
}
},
{
"multi_match": {
"query": "Smith",
"fields": [
"field1",
"field3",
"field5"
]
}
}
]
}
},
{
"bool": {
"filter": [
{
"type": {
"value": "type2"
}
},
{
"multi_match": {
"query": "Smith",
"fields": [
"field2",
"field4",
"field6"
]
}
}
]
}
}
]
}
}
}

ElasticSearch filtered query and filter term

I'm trying to use a filter on a filtered query, this is what I'm trying with Sense:
GET myindex/catalog/_search
{
"query": {
"filtered": {
"query": {
"query_string": {
"analyze_wildcard": true,
"query": "test",
"fields": ["title^3.5", "contributions.authors.name^5", "publisher^2", "formats.productCode^0.5", "description^0.1"],
"use_dis_max": true
}
},
"filter": {
"term": {
"sku": "test-687"
}
}
}
}
}
This query hasn't any hit, but if I remove the filter property I get exactly the item with sku = test-687.
I cannot understand why the query with the filter doesn't give me the same result.
Mapping:
{
"myindex": {
"mappings": {
"catalog": {
"properties": {
"sku": {
"type": "string"
},
"title": {
"type": "string"
},
"updated_at": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
}
}
}
}
}
}
the full query is:
GET myindex/catalog/_search {
"query": {
"filtered": {
"query": {
"query_string": {
"analyze_wildcard": true,
"query": "test",
"fields": ["title^3.5", "contributions.authors.name^5", "publisher^2", "formats.productCode^0.5", "description^0.1"],
"use_dis_max": true
}
},
"filter": {
"bool": {
"must": {
"query": {
"match": {
"sku": "test-687"
}
}
}
}
}
}
}
}
With default mapping the "Standard Analyser is used" :
An analyzer of type standard is built using the Standard Tokenizer with the Standard Token Filter, Lower Case Token Filter, and Stop Token Filter.
(More details her )
Term is case sensitive, match not

Find empty strings in elasticsearch

I'm trying to _search documents that has some specific value in the field.
{
"query": {
"bool": {
"must": [
{"field": {"advs.status": "warn"}}
]
}
}
}
That works find. But when I'm trying to find documents that has empty string in that field, I get this error:
ParseException[Cannot parse '' ...
and then - long list of what was expected instead of empty string.
I try this query:
{
"query": {
"bool": {
"must": [
{"term": {"advs.status": ""}}
]
}
}
}
It doesn't fails but finds nothing. It works for non empty strings instead. How am I supposed to do this?
My mapping for this type looks exactly like this:
{
"reports": {
"dynamic": "false",
"_ttl": {
"enabled": true,
"default": 7776000000
},
"properties": {
"#fields": {
"dynamic": "true",
"properties": {
"upstream_status": {
"type": "string"
}
}
},
"advs": {
"properties": {
"status": {
"type": "string",
"store": "yes"
}
}
},
"advs.status": {
"type": "string",
"store": "yes"
}
}
}
}
Or another way to do the same thing more efficiently is to use the exists filter:
"exists" : {
"field" : "advs.status"
}
Both are valid, but this one is better :)
You can try this temporary solution which works but isn't optimal - https://github.com/elastic/elasticsearch/issues/7515
PUT t/t/1
{
"textContent": ""
}
PUT t/t/2
{
"textContent": "foo"
}
GET t/t/_search
{
"query": {
"bool": {
"must": [
{
"exists": {
"field": "textContent"
}
}
],
"must_not": [
{
"wildcard": {
"textContent": "*"
}
}
]
}
}
}
Try using must_not with missing in your bool:
"must_not":{
"missing":{
"field":"advs.status",
"existence":true,
"null_value":true
}
}
If tou want to search for fields containing an empty string, either you change your mapping to set not_analyzed to this particular field or you can use a script filter:
"filter": {
"script": {
"script": "_source.advs.status.length() == 0"
}
}
I generally use a filter if the field is not analyzed. Here is snippet:
{
"filtered": {
"filter": {
"term": {
"field": ""
}
}
}
},
the "missing" does work only for null values or not being there at all. Matching empty string was already answered here: https://stackoverflow.com/a/25562877/155708

Resources