Elasticsearch: Minimum_should_match don´t return correctly - elasticsearch

I'm new to the elastic universe and I have a question about a query. I'll try to describe it here:
I have a document called 'store' with several stores registered and within each store item a list of customers:
loja {
nome,
telefone,
email,
clientes : [
{
nomeCliente,
telefone,
email
}
]
}
I need a query where I would have to return at least 1 pair of customers from the same registered store
For example:
I research 'Ana Maria', 'Sandra Maria' and 'Alberto Braz', where I would need to return the stores that have [Ana Maria and Sandra Maria] or [Ana Maria and Alberto Braz] or [Sandra Maria and Alberto Braz].
I did the search according to the dsl below, but the minimum_should_match clause is not respecting the limit of 2 m and returning results with only 1 record found.
Am I doing something wrong in the query?
Could you help me out on this one?
Query:
{
"query": {
"bool": {
"must": [
{
"nested": {
"query": {
"bool":{
"should": {
"match": {
"clientes.nomeCliente" : {
"query" : "ANA MARIA",
"type" : "phrase",
"operator": "and",
"slop" : 40
}
}
},
"should": {
"match":{
"clientes.nomeCliente" : {
"query" : "SANDRA MARIA",
"type" : "phrase",
"operator": "and",
"slop" : 40
}
}
},
"should": {
"match":{
"clientes.nomeCliente" : {
"query" : "ALBERTO BRAZ",
"type" : "phrase",
"operator": "and",
"slop" : 40
}
}
}
},"minimum_should_match": 2
},
"path": "clientes",
"inner_hits" : {
"size" : 10
}
}
}
]
}
}
}

For the should you need to use an array instead of an object. So, you query need to be something like this :
{
"query": {
"bool": {
"must": [
{
"nested": {
"query": {
"bool": {
"should": [
{
"match": {
"clientes.nomeCliente": {
"query": "ANA MARIA",
"type": "phrase",
"operator": "and",
"slop": 40
}
}
},
{
"match": {
"clientes.nomeCliente": {
"query": "SANDRA MARIA",
"type": "phrase",
"operator": "and",
"slop": 40
}
}
},
{
"match": {
"clientes.nomeCliente": {
"query": "ALBERTO BRAZ",
"type": "phrase",
"operator": "and",
"slop": 40
}
}
}
],
"minimum_should_match": 2
}
},
"path": "clientes",
"inner_hits": {
"size": 10
}
}
}
]
}
}
}
I could not check the parameters of the match query because I don't have the mapping and sample data. But you can check that part with your index directly.

Related

Filter query by length of nested objects. ie. min_child

I'm trying to filter my query by the number of nested objects found. The Elastic Search documentation mentions that using a script is an expensive task, so I've set out to do it with a score, though I can't seem to get the script to work either.
Here's my mappings:
"mappings": {
"properties": {
"dates" : {
"type" : "nested",
"properties" : {
"rooms" : {
"type" : "integer"
},
"timestamp" : {
"type" : "long"
}
}
},
"doc_id" : {
"type" : "text"
},
"distance" : {
"type" : "integer"
}
...
}
}
Here's some example data:
PUT /test/_doc/1
{
"doc_id": "1",
"distance": 1,
"dates": [
{
"rooms": 1,
"timestamp": 1
},
{
"rooms": 1,
"timestamp": 2
},
...
]
}
I'm filtering by the parents distance field, among others, and filtering the nested dates by their timestamps, and rooms. I need to filter all results to an exact number of nest dates found.
I tried to borrow from here.
This is my search query:
GET /test/_search
{
"query" : {
"function_score": {
"min_score": 20,
"boost": 1,
"functions": [
{
"script_score": {
"script": {
"source": "if (_score > 20) { return - 1; } return _score;"
}
}
}
],
"query": {
"bool" : {
"filter": [
{ "range": { "distance": { "lt": 5 }}},
{
"nested": {
"score_mode": "sum",
"boost": 10,
"path": "dates",
"query": {
"bool": {
"filter": [
{ "range": { "dates.rooms": { "gte": 1 } } },
{ "range": { "dates.timestamp": { "lte": 2 }}},
{ "range": { "dates.timestamp": { "gte": 1 }}}
]
}
}
}
}
]
}
}
}
}
}
This returns all the results that match, yet they all have a score of 0.0 and aren't getting filtered by the number of nested objects found.
If this is the right solution, how can I get this working? If not, how can I get a script to do it within this search?
Thanks!
Before getting started, keep in mind that the scoring function has changed between Elastic 6 and 7. You can find the updated code samples on this this gist.
Your question didn't outline the specifics of your search. Reading the code, it seems like you want to retrieve all documents where the distance is less than five, and the number of matching rooms is precisely 2. If this is correct, the code you submitted does not achieve this.
Reasons: your function score contains your primary condition and your condition on the number of matching rooms (it is quite tricky to mix both, though not impossible). To make things simpler, isolate them for the function score to be only applicable to the number of rooms.
Supposing you are using elastic 7+, this might work:
{
"_source": {
"includes": ["*"],
"excludes": ["dates"]
},
"query": {
"bool": {
"must": [
{"range": {"distance": {"lt": 5}}},
{
"function_score": {
"min_score": 20,
"boost": 1,
"score_mode": "multiply",
"boost_mode": "replace",
"functions": [
{
"script_score": {
"script": {
"source": "if (_score > 20) { return 0; } return _score;"
}
}
}
],
"query": {
"nested": {
"path": "date",
"boost": 10,
"score_mode": "sum",
"query": {
"constant_score": {
"boost": 1,
"filter": {
"bool": {
"should": [
{
"bool": {
"must": [
{"term": {"dates.timestamp": 1}},
{"range": {"dates.rooms": {"lt": 5}}}
],
"should": [
{"term": {"dates.other_prop": 1}},
{"term": {"dates.other_prop": 4}}
]
}
},
{
"bool": {
"must": [
{"term": {"dates.timestamp": 2}},
{"range": {"dates.rooms": {"lt": 5}}}
],
"should": [
{"term": {"dates.other_prop": 1}},
{"term": {"dates.other_prop": 3}}
]
}
}
]
}
}
}
}
}
}
}
}
]
}
}
}
I managed to get it all working with scoring as filtering doesn't allow scoring. Using GET /test/_explain/[id] helped to understand exactly what was happening
GET /test/_search
{
// Don't return the nested fields, they are returned in the inner_hits
"_source": {
"includes": [ "*" ],
"excludes": [ "dates" ]
},
"query": {
"function_score": {
// Score is calculated with 1 point for each matched inner property and outer property.
// 7 is the exact score to allow
"min_score": 7,
"boost": 1,
"score_mode": "sum",
"boost_mode": "multiply",
"functions": [
{
"script_score": {
"script": {
// Ignore any results that don't match exactly
"source": "if (_score == 7) { return 1; } return 0;",
"lang": "painless"
}
}
}
],
"query": {
"bool" : {
"must" : [
{ "range" : { "distance" : { "lt": 10 }}},
{
"nested": {
"inner_hits" : {},
"path": "dates",
"score_mode": "sum",
"query": {
"bool": {
// Match each required nested object individually, then verify with the score if we got 1 match for each should
"should": [
{
"bool": {
"must": [
{ "term": { "dates.timestamp": 1 }},
{ "range": { "dates.rooms": { "lt": 5 } } }
],
"should": [
{ "term": { "dates.other_prop": 1 }},
{ "term": { "dates.other_prop": 4 }}
]
}
},
{
"bool": {
"must": [
{ "term": { "dates.timestamp": 2 }},
{ "range": { "dates.rooms": { "lt": 5 } } }
],
"should": [
{ "term": { "dates.other_prop": 1 }},
{ "term": { "dates.other_prop": 3 }}
]
}
}
]
}
}
}
}
]
}
}
}
}
}

nested boolean with match query in elasticsearch

I would like to match within a boolean query in Elasticsearch. I have the match query and boolean query working as expected now, but I am not sure how to have a AND to combine them.
nested boolean
{
"query": {
"constant_score" : {
"filter":{
"bool":{
"must":[
{"terms":{"address.keyword": addr}},
{"bool":{
"should":[
{"terms": {"state.keyword": state}}
,{"terms": {"city.keyword": city}}
]
}}
]
}
}
}}}
match
{"query": {
"match": {
"auct_title": {
"query": keyword,
"operator": "and"
}
}
}
, "collapse" : {
"field" : "id"
}
,"sort" : [
{ sort_field: {"order" : sort_order} }]
,"size":20
}
You can move natch to the must clause . So document has to satisfy three conditions
1.address
2.either of state/city
2.match on auct_title
It will then return one document per Id based on sort order passed
GET <index>/_search
{
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"term": {
"address.keyword": "addr"
}
},
{
"bool": {
"should": [
{
"term": {
"state.keyword": "state"
}
},
{
"term": {
"city.keyword": "city"
}
}
]
}
},
{
"match": {
"auct_title": {
"query": "keyword",
"operator": "and"
}
}
}
]
}
}
}
},
"collapse": {
"field": "id"
},
"sort": [
{
"FIELD": {
"order": "desc"
}
}
],
"size": 20
}

ElasticSearch filtered bool query not working with multi_match

I have this installed on Ubuntu running ElasticSearch 6.2.3
I am new to ES so if this is duplicate or obvious I am sorry.
I just need to do a contains query that filters out items not marked as PUBLISHED.
Here is what i think should be returning the correct results but it returns nothing (0 hits):
GET /index/type/_search
{
"query": {
"bool" : {
"must" : {
"multi_match" : {
"query": "Funny black cat",
"operator": "and",
"fields": [ "title", "description"]
}
},
"filter": {
"term" : { "publishStatus" : "PUBLISHED" }
}
}
}
}
Furthermore, this simple filter query is also return 0 records...
GET /index/type/_search
{
"query": {
"bool": {
"filter": {
"term": {
"publishStatus": "PUBLISHED"
}
}
}
}
}
Well this is what worked for me (stopped using filter, changed to match):
GET index/type/_search
{
"query": {
"bool":{
"must":[
{
"multi_match" : {
"query": "dinner sydney",
"fields": [ "title^3", "description" ],
"operator": "and"
}
},{
"match": { "publishStatus": "PUBLISHED"}
}
]
}
}
}

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 | Match multiple phrases

Im trying to create a query that will find all statuses that contain either #breakingbad OR "breaking bad"
here is what i have so far , but its obviously wrong according to sense:
{
"query": {
"match": {
"_all": {
"query": "breaking bad",
"type": "phrase"
}
},
"match": {
"_all": {
"query": "#breakingbad",
"type": "phrase"
}
}
}
ANSWER:
{
"query": {
"bool": {
"should": [
{
"match": {
"message": {
"query": "breaking bad",
"type": "phrase"
}
}
},
{
"match": {
"message": "#poznasty"
}
}
]
}
}
}
why not use multi_match
{
"query" : {
"multi_match" : {
"fields" : ["name", "description"],
"query" : "breaking bad",
"type" : "phrase_prefix"
}
}
}
MultiMatchQueryBuilder builder = QueryBuilders.multiMatchQuery(query,
"name", "description").type(MatchQueryBuilder.Type.PHRASE_PREFIX);

Resources