Difference between Query Context and Filter Context while Querying - elasticsearch

What is the difference between the Query Context and the Filter Context in the Elastic Search in Query DSL.
My Understanding is Query Context- How well the document matches the query parameters.
Ex:
{ "match": { "title": "Search" }}
If I am searching for the documents with title 'Search' then if I contains two documents
i)title:"Search"
ii)title:"Search 123"
Then first document is a perfect match and document two is a semi-match. Then the first document is given in the first place and the second document given the second place. Is my understanding correct?
Filter Context:
Ex:
{ "term": { "status": "published" }}
If I am searching for the documents with status 'published' then if I contains two documents
i)status:"published"
ii)status:"published 123"
Then the first document is perfect so it is returned and the second match is not a perfect match so it is not returned. Is my understanding correct?

Basically in Query context, the elastic search scans all the documents and tries to find out how well the documents match the query, means the score will will be calculated for each documents. Where as in filter context,it will just checks whether the documents matches the query or not i.e, only yes or no will be returned. The filter queries does not contribute to the score of the document.
Next coming to the difference between the match and term queries , if you mapped a field to keyword then that field will be not analysed and its inverted index contains the whole term as it is, i.e is if status is mapped to keyword then if you insert "published 123" in status field , then its inverted index contains ["published 123"] and if status is mapped to text then while inserting data to status filed it is analysed for ex: if you insert "published 123" then its inverted index will be ["published","123"].
So whenever you use term query for keyword fields the query string will not be analysed and it tries to find exact term in the inverted index and if you use match query it analyses the query string and it returns all the doc's that contain the one of the analysed string of query in it's inverted index

Your understanding about the difference between term and match queries is correct at the most basic level but like Jettro commented in the filter query you mentioned both the documents will be selected. When doing a term query it really depends what kind of analyzer you are using and how that affects the terms that are stored in inverted index that lucene uses.
To quote an example from the Elasticsearch: Th Definitive Guide "if you were to index ["Foo","Bar"] into an exact value not_analyzed field, or Foo Bar into an analyzed field with the whitespace analyzer, both would result in having the two terms Foo and Bar in the inverted index."
Now under the hood the term query will search all the terms in the inverted index for your query term and even if one of them matches it will be returned as a result.
So in the first case there is only "published" in the inverted index but in the second case too there are both terms "published" and "123", so both documents will be returned as matches.
It also is important to remember that the term query looks in the inverted index for the exact term only; it won’t match any variants like "Published" or "publisheD" with "published".

Related

Elasticsearch - match by all terms but full field must be matched

I'm trying to improve search on my service but get stuck on complex queries.
I need to match some documents by terms but return only documents that contains all of provided terms in any order and contains only this terms.
So for example, lets take movie titles:
"Jurassic Park"
"Lost World: Jurassic Park"
"Jurassic Park III"
When I type "Park Jurassic" I want only first document to be returned because it contains both words and nothing more.
This is silly example of complex problem but I've simplified it.
I tried with terms queries, match etc but I don't know how to check if entire field was matched.
So in short it must match all tokens in any order.
Field is mapped as text and also as keyword.
You tested the terms set query?
Returns documents that contain a minimum number of exact terms in a
provided field.
The terms_set query is the same as the terms query, except you can
define the number of matching terms required to return a document.

Why does elastic search analyze a document 2 times?

From what I've understood, When I index a document say:
PUT <index>/_doc/1
{
"title":"black white fox cat"
}
Elastic search analyzes this via a standard analyzer and turns the title into an array of tokens.
But then when I search for this document let's say
POST <index>/_search
{
"query":
{
"match":
{
"title":"black"
}
}
}
It analyzez again via the same analyzer, isn't that inefficient?
It's not efficient, its necessary step to provide the search results.
let me explain under the hood, how search and index process works.
Index tokenize the text based on data type, and configured analyzer and index the tokens into the inverted index.
Search terms again is tokenised based on the query type(no tokens in case of term family of queries), and search generated tokens into the inverted index created at index time(step-1).
Tokens match process(matching index time tokens in the inverted index to the tokens generated at the query time), is what finds the matches documents and provides the search results, normally this tokens match is a exact string match process, with the exception in some cases like (prefix query, wildcard query etc). and as its a exact string match, its very fast and optimized process.
There are various use-cases, like when you use the keywords data type, text is not analyzed and when you use term level queries search time analysis doesn't happen.
Now, important thing to not is that during search time also same analyzer used at index time, otherwise it would end up generating different token which not produce match in step-3 Described earlier.

ElasticSearch: term vs match query decision

Being new to ElasticSearch, need help in my understanding.
What I read about term vs match query is that term query is used for exact match and match query is used when we are searching for a term and want result based on a relevancy score.
But if we already defined a mapping for a field as a keyword, why anyone has to decide upon between term vs match, wouldn't it be always a term query in case mapping is defined as a keyword?
What are the use cases where someone will make a match query on the keyword mapping field?
The same confusion is vice versa.
A text field will be analyzed (transformed, split) to generate N tokens, and the keyword itself will become a token with no transformations. At the end, you have N tokens referencing a document.
Then.
By doing a match query, you will treat your query as a text as well, by analyzing it before performing the matching (transforming it), and the term will not.
You can create a field with a term mapping, but then perform a match query on top of it (for example if you want to be case insensitive), and you can create a text mapping for a n-gram and perform a term query to match exactly what you're asking for.

Elastic search giving strange results

I am following this tutorial on elastic search.
Two employees have 'about' value as:
"about": "I love to go rock climbing"
"about": "I like to collect rock albums"
I run following query:
GET /megacorp/employee/_search {"query":{"match":{"about":"rock coll"}}}
Both above entries are returned, but surprisingly wit same score:
"_score": 0.2876821
Shouldn't the second one must have higher score as it has 'about' value containing both 'rock' and 'coll' while first one only contains 'rock'?
That totally depends on what analyzer you are using. if you are using standard or english analyzer this result is correct. I recommend you to spend some time working with elasticsearch's Analyze API to get familiar how each analyzer affect your text.
By the way, if you want second document to have higher score, take a look at Partial matching.
When we search on a full-text field, we need to pass the query string through the same analysis process as we have when we index a document, to ensure that we are searching for terms in the same form as those that exist in the index.
Analysis process usually consists of normalization and tokenization (the string is tokenized into individual terms by a tokenizer).
As for match Query:
If you run a match query against a full-text field, it will analyze the query string by using the correct analyzer for that field before executing the search. It just looks for the words that are specified.
So, in your match query Elasticsearch will look for occurrences of the whole separate words: rock or/and coll.
Your 2nd document doesn't contain a separate word coll but was matched by the word rock.
Conclusion: the 2 documents are equivalent in their _score value (they were matched by the same word rock)
Elasticsearch analyzes each text field before storing it. The default analyzer (standard analyzer) splits the text based on whitespaces and lowercases it. The output of analysis process is a list of tokens which are used to match your query tokens. If any of the tokens match exactly the relevant document is returned. That's being said, your second document doesn't contain the token col and that's why you are having the same score for both documents.
Even if you build your custom analyzer and use stemming, the word collect won't be stemmed as coll.
You can build custom analyzers in which you can specify that tokens should be of length 1 character, then Elasticsearch will consider each single character as a token and you can search for the existence of any character in your documents.

ElasticSearch highlighting the matched part in query

I'm sending a match query to ElasticSearch and I'm getting back documents whose matching fields have been highlighted. What I'm trying to do is to map a set of documents to the matching substring in query.
For example, assuming I query with "quick brown". I want to map the document "quick silver" to "quick", "brown fox" to "brown" and "mr brown" to "brown".
This is trivial if document fields exactly contain the word in query. But things get messy when I use fuzziness, synonyms, asciifolding etc. In that case, the highlighted parts of search results might not even appear in my search query.
Is is possible to achieve this task without replicating the analyzer logic on my application?
Use the simple query string query instead of the match query when you try to find mapped documents. And set the operator to or. So quick silver as a query will match docs with quick or silver.

Resources