ElasticSearch highlighting the matched part in query - elasticsearch

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.

Related

How to search exact word in a test in Elastic Search

Let's say I have two texts:
Text 1 - "The fox has been living in the wood cabin for days."
Text 2 - "The wooden hammer is a dangerous weapon."
And I would like to search for the word "wood", without it matching me "wooden hammer". How would I do that in Elastic Search or nest?
Term query is used for exact matches search. However it's not recommended to use it against text fields, the following quote from term query documentation:
To better search text fields, the match query also analyzes your
provided search term before performing a search. This means the match
query can search text fields for analyzed tokens rather than an exact
term.
The term query does not analyze the search term. The term query only
searches for the exact term you provide. This means the term query may
return poor or no results when searching text fields.
The problem with text exact matches, as described in the Term query documentation:
By default, Elasticsearch changes the values of text fields as part of
analysis. This can make finding exact matches for text field values
difficult.
So, the documents data is modified (i.e., analyzed) before indexing. This depends on the index mapping definition for each field, defaults to the default index analyzer, or the standard analyzer.
But the default standard analyzer will not change the token "Wooden" to "Wood", this might happen if you used stemming for this field.
This means, if you don't use a different analyzer or stemming, querying with "Wood" shouldn't match "Wooden" token.
To summarize: Indexed data is modified/analyzed before indexing (based on the field mapping definition). Match query analyze the search query, while Term query doesn't analyze the search query. So you have to properly chose the field mapping and the search query to better suit your use case
For some use cases, like storing email addressed, phone numbers or keyword fields that always have the same value, consider using the Keyword type, which is suitable for exact matches in these use cases. However, ES recommends:
Avoid using keyword fields for full-text search. Use the text field
type instead.
So for better visibility and practical solution for your use case, it's better to elaborate more the field mapping you use and what you want to achieve.

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.

How do I match a partial result with Elastic Search?

I'm trying to find out how to properly write my query in order to do a LIKE query with ElasticSearch.
Let's say I have a record of firstname and I want to find every one where there is ma in it.
So I've tried multiple things but none are working. Here is a list :
{"match": {"text": ".*ma.*"}}
{"match": {"text": "*ma*"}}
{"match":{"text"{"query":"ma","fuzziness":"AUTO","prefix_length":1}}}
Do you have an idea of how to do that or where am I missing something?
You might look into using the N-Gram tokenizer to split your documents' tokens up into their substrings.
This will allow you to search against the index with the "partial" matches you're describing.
Bear in mind that this will affect how your documents are tokenized for search so, if you are using other types of analysis for other parts of your application, you may want to create additional fields for your N-Gram tokenized values (or even create a separate index for them).
As a rule of thumb, always try to optimize your index for the queries you want to perform, rather than trying to solve your search problems at query time.

Difference between Query Context and Filter Context while Querying

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".

Resources