query_string query doesn't take word order into consideration - elasticsearch

I have the following documents:
{ _id: 1, name: "ello worl" }
{ _id: 2, name: "world hello" }
{ _id: 3, name: "hello world" }
When I execute the following query:
{
"query": {
"query_string": {
"query": "​*ello* *worl*"
}
}
}
Documents are ordered in the same order as above, but I was expecting them to be in 1) 3) 2) order.
My question is: Why doesn't the third document have higher score than the second one?
P.S. Using wildcards is mandatory.

So it turns out that it is impossible to sort documents by relevance with wildcards out of the box in elasticsearch. So the workaround that I found is to do a boolean query with multiple should leaf queries each of which performs a wildcard search in itself with different boosts.
{
"query": {
"bool": {
"should": [
{ query_string: { query: "ello worl", boost: 4 } },
{ query_string: { query: "ello* worl*", boost: 3, analyze_wildcard: true } },
{ query_string: { query: "*ello *worl", boost: 2, analyze_wildcard: true } },
{ query_string: { query: "*ello* *worl*", analyze_wildcard: true } }
]
}
}
}

Related

Aggreagate results based on 3 different elasticsearch queries

I have 3 different search queries coming from different sources, I want to aggregate these queries in to a single query that will return the results that is union of these 3 queries (OR operation on query)
For example:
Query 1:
query: {
bool: {
filter: [
{ terms: { tags.keyword: ['apple', 'banana'] }},
{ terms: { language.keyword: ['en'] }},
]
}
}
Query 2:
query: {
bool: {
filter: [
{ terms: { tags.keyword: ['orange', 'mango'] }},
{ terms: { language.keyword: ['it'] }},
{ terms: { source.keyword: ['Royal Garden'] }},
]
}
}
Query 3:
query: {
bool: {
filter: [
{ terms: { owner.keyword: ['Dan Chunmun'] }},
{ terms: { language.keyword: ['en'] }},
{ terms: { source.keyword: ['Royal Garden'] }},
]
}
}
I what to have the search result that is:
Result = Query 1 OR Query 2 OR Query 3 (Union of all 3 queries)
I was looking at How to combine multiple bool queries in elasticsearch question, but there it is not explained how to merge the query.
I tried using should clause but not able to get the expected result so far.
I tried combining the bool part of the queries above like:
const boolTerms: any = [];
Queries.map(q => {
return boolTerms.push(q.query);
});
// combined query
filter : {
bool: {
should: boolTerms
}
}
There are two ways for combining queries
Query string query is meant for these use cases only. In query string query you can write each and every query in a string format
Let define a clause A=tags.keyword: ['apple', 'banana']
Now way you can combine multiple is this
{
"query": {
"query_string": {
"query": "(A and B) OR (D and E and F) or(G and H and E)"
}
}
}
Here A and B are all clauses of query 1.
But since query string query is a full-text query and analyzers will be applied to query terms, so for your case bool query would be used, in which you can combine tern queries as well
Here is an Example
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"terms": {
"tags.keyword": ["apple", "banana"]
}
},
{
"terms": {
"language.keyword": ["en"]
}
}
]
}
},
{
"bool": {
"must": [
{
"terms": {
"tags.keyword": ["orange", "banana"]
}
},
{
"terms": {
"language.keyword": ["it"]
}
}
]
}
}
]
}
}
}

Elasticsearch: Full match of query value from beginning to end of field

I have problem with full match querying of field value. title and gender - fields of indexed docs
query: {
query_string: {
query: "box AND gender:\"women\"",
default_field: "title"
}
}
I use double quotes to match full query for gender. But if there is gender "men,women" with title 'box' it also will be in results. I know, that elasticsearch does not support regexp characters ^ and $ for beginning and end of the string, so I couldn't make /^women$/.
What do I need to do if I want docs matching only 'women' gender, not 'men,women' ?
Q:
What do I need to do if I want docs matching only 'women' gender, not 'men,women' ?
For exact searches you should use a terms query rather than a fulltext-search query like the query_string. So to get all documents that matches exactly gender == women you should do it like so:
GET your-index/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"gender.keyword": {
"value": "women"
}
}
}
]
}
}
}
Please be aware that this query assumes that the gender-field is also mapped as a keyword.
To complete the query you would add another must-clause to get all documents that have box in the title field women as the value of the gender-field.
GET your-index/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"gender.keyword": {
"value": "women"
}
}
},
{
"match": {
"title": "box"
}
}
]
}
}
}
Thank you apt-get_install_skill. Keyword did the work, but with some addings.
Summary this is solution:
query: {
bool: {
must: {
query_string: {
query: "box",
default_field: "title"
}
},
filter: {
bool: {
should: [
{term: {"gender.keyword": "women"}}
]
}
}
}
}
I need should as array for searching multiple genders if I will need it. For example, some docs have unisex gender, such as 'women,men'
Example with multiple genders:
query: {
bool: {
must: {
query_string: {
query: "box",
default_field: "title"
}
},
filter: {
bool: {
should: [
{term: {"gender.keyword": "women"}},
{term: {"gender.keyword": "kids"}}
#summary it may be gender 'girls'
]
}
}
}
}

Elasticsearch - Sort query based on collapse results

I'm trying to group/stack items based on their SKU.
Currently if sorting from high to low, an item thats being sold for $10 or $1, will show the $1 item first (because it's also sold for $10 it will be placed in front of the array ofcourse). The sorting should only respect the lowest_price for its sorting operation, for only that specific SKU.
Is there a way so I can do sorting based on the lowest_price of for every SKU and only return 1 single item per SKU?
If the results from the collapse could be used as variable for the sorting, this could be solved but I haven't been able to find out how this work.
My item object looks like this:
{
itemId: String,
sku: String,
price: Number
}
This is my query:
let itemsPerPage = 25;
let searchQuery = {
from: itemsPerPage * page,
size: itemsPerPage,
_source: ['itemId'],
sort: [{'sale.price': 'desc'}],
query: {
bool: {
must: [],
must_not: []
}
},
collapse: {
field: 'sku',
inner_hits: [{
name: 'lowest_price',
size: 1,
_source: ['itemId'],
sort: [{
'price': 'asc'
}]
}
],
}
};
You need to add sort underneeth collapse.
example:
GET /test/_search
{
"query": {
"function_score": {
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"match" : {
"job_status" : "SUCCESS"
}
}
]
}
}
}
}
}
},
"collapse": {
"field": "run_id.keyword"
},
"sort": [
{
"#timestamp": {
"order": "desc"
}
}
]
}
This may solve your issue.

Elasticsearch match against filter only

We have a multi-tenant index and need to perform queries against the index for a single tenant only. Basically, for all documents that match the filter, return any documents that match the following query, but do not include documents that only match the filter.
For example, say we have a list of documents document like so:
{ _id: 1, account_id: 1, name: "Foo" }
{ _id: 2, account_id: 2, name: "Bar" }
{ _id: 3, account_id: 2, name: "Foo" }
I thought this query would work but it doesn't:
{
"bool": {
"filter": { "term": { "account_id": 2 } },
"should": [
{ "match": { "name": "Foo" }
]
}
}
It returns both documents matching account_id: 2:
{ _id: 3, account_id: 2, name: "Foo", score: 1.111 }
{ _id: 2, account_id: 2, name: "Bar", score: 0.0 }
What I really want is it just to return document _id: 3, which is basically "Of all documents where account_id is equal to 2, return only the ones whose names match Foo".
How can I accomplish this with ES 6.2? The caveat is that the number of should and must match conditions are not always known and I really want to avoid using minimum_should_match.
Try this instead: simply replace should by must:
{
"bool": {
"filter": { "term": { "account_id": 2 } },
"must": [
{ "match": { "name": "Foo" }
]
}
}

Elastic search returning wrong results

I am running a query against elastic search but the results returned are wrong. The idea is that I can check against a range of fields with individual queries. But when I pass the following query, items which don't have the included lineup are returned.
query: {
bool: {
must: [
{match:{"lineup.name":{query:"The 1975"}}}
]
}
}
The objects are events which looks like.
{
title: 'Glastonbury'
country: 'UK',
lineup: [
{
name: 'The 1975',
genre: 'Indie',
headliner: false
}
]
},
{
title: 'Reading'
country: 'UK',
lineup: [
{
name: 'The Strokes',
genre: 'Indie',
headliner: true
}
]
}
In my case both of these events are returned.
The mapping can be seen here:
https://jsonblob.com/567e8f10e4b01190df45bb29
You need to use match_phrase query, match query is looking for either The or 1975 and it find The in The strokes and it gives you that result.
Try
{
"query": {
"bool": {
"must": [
{
"match": {
"lineup.name": {
"query": "The 1975",
"type": "phrase"
}
}
}
]
}
}
}

Resources