Querying Specific List Indexes In Elastic Search - elasticsearch

So I have an search query in Elasticsearch which queries a field called myList. Inside that list are elements. elm1, elm2, and elm3. I want to be able to query that list such that all the elements must match. For example:
myList: [{
elm1: "value1",
elm2: "value2",
elm3: "value4"
},
{
elm1: "value2"
elm2: "value3"
elm3: "value3"
},
{
elm1: "value3",
elm2: "value4",
elm3: "value5"
}]
If I construct a query such that it searches for the field: elm1 = value1 and elm2 = value2 and elm3=value3,
"query": {
"bool": {
"must": [],
"filter": [
{
"bool": {
"filter": [
{
"bool": {
"should": [
{
"query_string": {
"fields": [
"myList.elm1.keyword"
],
"query": "value1"
}
}
],
"minimum_should_match": 1
}
},"bool": {
"filter": [
{
"bool": {
"should": [
{
"query_string": {
"fields": [
"myList.elm2.keyword"
],
"query": "value2"
}
}
],
"minimum_should_match": 1
}
},"bool": {
"filter": [
{
"bool": {
"should": [
{
"query_string": {
"fields": [
"myList.elm3.keyword"
],
"query": "value3"
}
}
],
"minimum_should_match": 1
}
}
}
]
}
}
It will return true because
myList[0]['elm1']=value1
myList[0]['elm2']=value2
myList[1]['elm3']=value3
This is not what I want.
How do I get it such that
myList[x]['elm1']=value1
myList[y]['elm2']=value2
myList[z]['elm3']=value3
Where x=y=z

When you're deailing with arrays of objects, these objects get flattened and essentially lose the connections between each other.
You should use the nested field type instead:
PUT elms_deep
{
"mappings": {
"properties": {
"myList": {
"type": "nested"
}
}
}
}
then re-add your documents:
POST elms_deep/_doc
{
"myList": [
{
"elm1": "value1",
"elm2": "value2",
"elm3": "value4"
},
{
"elm1": "value2",
"elm2": "value3",
"elm3": "value3"
},
{
"elm1": "value3",
"elm2": "value4",
"elm3": "value5"
}
]
}
and then proceed with the 3 nested term queries -- no need for your original query_string queries when you're targeting .keyword fields:
POST elms_deep/_search
{
"query": {
"bool": {
"filter": [
{
"nested": {
"path": "myList",
"query": {
"term": {
"myList.elm1.keyword": {
"value": "value1"
}
}
}
}
},
{
"nested": {
"path": "myList",
"query": {
"term": {
"myList.elm2.keyword": {
"value": "value2"
}
}
}
}
},
{
"nested": {
"path": "myList",
"query": {
"term": {
"myList.elm3.keyword": {
"value": "value3"
}
}
}
}
}
]
}
}
}

So Joe's answer is nearly there, he's right you need to use the nested field type. His answer gives the possibility of
myList[x]['elm1']=value1
myList[y]['elm2']=value2
myList[z]['elm3']=value3
Where x,y,z are independent elements.
If you want x=y=z:
{
"query": {
"nested": {
"path": "myList",
"query": {
"bool": {
"filter": [
{
"term": {
"myList.elm1.keyword": {
"value": "value1"
}
}
},
{
"term": {
"myList.elm1.keyword": {
"value": "value1"
}
}
},
{
"term": {
"myList.elm1.keyword": {
"value": "value1"
}
}
}
]
}
}
}
}
}

Related

elastic search match on multiple fields

I need to retrieve documents that match the following criteria:
{ "field1: "string1" AND "field2": "string2"}
OR
{ "field1: "string3" AND "field2": "string4"}
OR
{ "field1: "string5" AND "field2": "string6"}
I can do that for one set of conditions like this
How to achieve that for multiple sets in a single query?
You can simply wrap all your OR conditions in a bool/should query:
{
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"bool": {
"must": [
{
"match": {
"field1": "string1"
}
},
{
"match": {
"field2": "string2"
}
}
]
}
},
{
"bool": {
"must": [
{
"match": {
"field1": "string3"
}
},
{
"match": {
"field2": "string4"
}
}
]
}
},
{
"bool": {
"must": [
{
"match": {
"field1": "string5"
}
},
{
"match": {
"field2": "string6"
}
}
]
}
}
]
}
}
}

How to query for empty field or specific value

I'm trying write a query to achieve the following result:
field1: value1 AND
field2: value2 OR "" (empty)
I've tried the following but it always returns me empty results:
{
"_source": ["field1", "field2"],
"query": {
"bool": {
"must": [
{"match": { "field1": "value1" }},
{
"bool": {
"should": [
{
"match": {
"field2": "value2"
}
}
],
"must_not": [
{
"exists": { "field": "field2" }
}
]
}
}
]
}
}
}
I believe I'm making a query that contradicts itself.
This is looking very complicated.
Try using queryStringQuery
Try rewriting your query like this
{
"_source": ["field1", "field2"],
"query": {
"query_string": {
"query": "field1:value1 AND (field2:value2 OR (!field2:*))"
}
}
}
If you still want to use in this format
You have used must_not clause which would mean somewhat this as below according to your use case.
field1: value1 AND
field2: value2 AND NOT "" (empty)
What you should do is
{
"_source": [
"field1",
"field2"
],
"query": {
"bool": {
"must": [
{
"match": {
"field1": "value1"
}
},
{
"bool": {
"should": [
{
"match": {
"field2": "value2"
}
},
{
"bool": {
"must_not": [
{
"exists": {
"field": "field2"
}
}
]
}
}
]
}
}
]
}
}
}
But it would be more easy for you to use queryString if you want to analyze the terms in query first which you have done in your query.
So using queryString OR bool in your this case would be same

Mutiple query_strings (nested and not nested)

I have got the following index:
{
"thread":{
"properties":{
"members":{
"type":"nested",
"properties":{
"memberId":{
"type":"keyword"
},
"firstName":{
"type":"keyword",
"copy_to":[
"members.fullName"
]
},
"fullName":{
"type":"text"
},
"lastName":{
"type":"keyword",
"copy_to":[
"members.fullName"
]
}
}
},
"name":{
"type":"text"
}
}
}
}
I want to implement a search, that finds all threads, that either match the members name or the thread name, as long as the user id matches.
My current query looks like this:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "members",
"score_mode": "none",
"query": {
"bool": {
"filter": [
{ "match": { "members.id": "123456789" } }
]
}
}
}
},
{
"nested": {
"path": "members",
"query": {
"bool": {
"must": {
"simple_query_string": {
"query": "Rhymen",
"fields": ["members.fullName"]
}
}
}
}
}
}
]
}
}
}
Can I filter the members and thread names in one query or do I have to merge two separate queries? I tried adding a "should" with "minimum_should_match: 1" so I could add a second not nested "query_string". But that didn't work as expected (scores were pretty screwed).
yeah i think this should work.
you have to keep the concern for filter memberId in both the filters. Nested filter will need it to match the user with memberId and name.
{
"query": {
"bool": {
"must": [{
"nested": {
"path": "members",
"query": {
"term": {
"members.memberId": {
"value": 1
}
}
}
}
},
{
"bool": {
"should": [{
"term": {
"name": {
"value": "thread_name"
}
}
},
{
"nested": {
"path": "members",
"query": {
"bool": {
"should": [{
"term": {
"members.fullName": {
"value": "trump"
}
}
},
{
"term": {
"members.memberId": {
"value": 1
}
}
}
]
}
}
}
}
]
}
}
]
}
}
}

elasticsearch boost query in feild having multiple value

I have some document in elasticsearch index. Here is the sample document
DOC1
{
"feild1":["hi","hello","goodmorning"]
"feild2":"some string"
"feild3":{}
}
DOC2
{
"feild1":["hi","goodmorning"]
"feild2":"some string"
"feild3":{}
}
DOC3
{
"feild1":["hi","hello"]
"feild2":"some string"
"feild3":{}
}
I want to query for feild1 having values "hi" and "hello" if both is present then that document should come first if any one is present then it should come after that.
for example:
result should be in order of DOC1, DOC3, DOC2. I tried with boost query. but it is retuning not in the order that I want. Here is the query that I am trying.
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"avail_status": true
}
},
{
"bool": {
"should": [
{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hi"
]
}
},
"boost": 20
}
},
{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hello"
]
}
},
"boost": 18
}
}
]
}
}
]
}
}
}
this is returning me first those document having "hi" and then those having "hello". Thanks in advance!
To add extra boost for documents with larger field1, you can put funtion_score script score.
Mappings
{
"mappings": {
"document_type" : {
"properties": {
"field1" : {
"type": "text",
"fielddata": true
},
"field2" : {
"type": "text"
},
"field3" : {
"type": "text"
}
}
}
}
}
Index documents
POST custom_score_index1/document_type
{
"feild1":["hi","hello","goodmorning"],
"feild2":"some string",
"feild3":{}
}
POST custom_score_index1/document_type
{
"feild1":["hi","goodmorning"],
"feild2":"some string",
"feild3":{}
}
POST custom_score_index1/document_type
{
"feild1":["hi","hello"],
"feild2":"some string",
"feild3":{}
}
Query with function score add extra _score for larger size for field1
POST custom_score_index1/document_type/_search
{
"query": {
"function_score": {
"query": {
"bool": {
"must": [{
"match_phrase": {
"avail_status": true
}
},
{
"bool": {
"should": [{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hi"
]
}
},
"boost": 20
}
},
{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hello"
]
}
},
"boost": 18
}
}
]
}
}
]
}
},
"functions": [{
"script_score": {
"script": {
"inline": "_score + 10000 * doc['field1'].length"
}
}
}],
"score_mode": "sum",
"boost_mode": "sum"
}
}
}

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