Elasic search: find doc by id and highlight words based on query string - elasticsearch

I like to find an document in elastic search an highlight terms based on an query string.
Is this possible?
I tried to run an query-string elastic search and filter the result based on ID. But those sounds not very efficient, because elastic first generates an huge list of all document matched the querystring (which could by millions) an pic only one document based on the filter.
Is there a way or query-contstruct to combine querystring and "search for term in _id field" in one boolean search?
Something like this (which is not working):
"query": {
"bool": {
"must": {
"query_string": {
"query": "red*",
"fields": [
"text",
"title"
]
},
"term": {
"_id":"fda72434fa172"
}
}
}
},
"highlight": {
"fields": {
[...]

I made a small example that can be a starting point.
Use filter to perform your query and retrieve the doc by id.
Then I used match and highlight to highlight the term I want.
POST test/_doc/fda72434fa172
{
"text": "I like to find an document in elastic search an highlight terms based on an query string. Is this possible?"
}
GET test/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"_id": "fda72434fa172"
}
}
],
"must": [
{
"match": {
"text": {
"query": "elastic search"
}
}
}
]
}
},
"highlight": {
"fields": {
"text": {}
}
}
}

Related

Elasticsearch: alternative to cross_fields with fuzziness

I have an elasticsearch index with the standard analyzer. I would like to perfom search queries containing multiple words, e.g. human anatomy. This search should be performed across several fields:
Title
Subject
Description
All the words in the query should be present in any of the fields (e.g. 'human' in title and 'anatomy' in description, etc.). If not all the words are present across these fields, the result shouldn't be returned.
Now, more importantly, I want to get fuzzy matches (for example, these queries should return approximately the same results as human anatomy:
human anatom
human anatomic
humanic anatomic
etc.
So fuzziness should apply to every word in the query.
As Elasticsearch doesn't support fuzziness for the multi-match cross-fields queries, I have been trying to achieve the desired behaviour this way:
{
"query": {
"bool" : {
"must": [
{
"query": {
"bool":
{
"should": [
{
"match": {
"title": {
"query": "human",
"fuzziness": 2,
}
}
},
{
"match": {
"description": {
"query": "human",
"fuzziness": 2,
}
}
},
{
"match": {
"subject": {
"query": "human",
"fuzziness": 2,
}
}
},
]
}
}
},
{
"query": {
"bool":
{
"should": [
{
"match": {
"title": {
"query": "anatomy",
"fuzziness": 2,
}
}
},
{
"match": {
"description": {
"query": "anatomy",
"fuzziness": 2,
}
}
},
{
"match": {
"subject": {
"query": "anatomy",
"fuzziness": 2,
}
}
},
]
}
}
},
]
}
}
}
The idea behind this code is the following: find the results where
either of the fields contains human (with 2-letter edit distance, e.g.: humane, humon, humanic, etc.)
and
either of the fields contains anatomy (with 2-letter edit distance, e.g.: anatom, anatomic, etc.).
Unfortunately, this code does not work and fails to retrieve a great number of relevant results. For example (the edit distance between each of the words in the two queries <= 2):
human anatomic – 0 results
humans anatomy – 21 results
How can I make fuzziness work within the given conditions? Recreating the index with n-gram is currently not an option, so I would like to make fuzziness work.

Elasticsearch boolean query doesn't work with filter

I'm not very strong in Elasticsearch. I'm trying to set up search in my app and got some strange problems. I have two documents:
{
"title": "Second insight"
"content": "Bla bla bla"
"library": "workspace"
}
{
"title": "Test source"
"content": "Bla bla bla"
"library": "workspace"
}
Then, I want to be able to make a search by text fields like title and content and apply some filters on fields like library. I have a query:
{
"query": {
"bool": {
"should": [
{ "match": { "title": "insight" }}
],
"filter": [
{
"term": {
"library": "workspace"
}
}
]
}
}
}
Despite the fact that I clearly defined title to be matched to insight, the query above returns both documents, not only the first one.
If I remove filter block:
{
"query": {
"bool": {
"should": [
{ "match": { "title": "insight" }}
]
}
}
}
the query returns correct results.
Then, I also tried to make a partial search. For some reasons, the query uses ins instead of insight below doesn't work, so, it returns empty list:
{
"query": {
"bool": {
"should": [
{ "match": { "title": "ins" }}
]
}
}
}
How should I make partial search? And how can I set up filters correctly? In other words, how to make a search partial query by some fields, but at the same time filtered by other fields?
Thanks.
You need to supply minimum_should_match in your first query.
I did the following and only got a single document (your desired outcome)
POST test_things/_search
{
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"match": {
"title": "insight"
}
}
],
"filter": [
{
"term": {
"library": "workspace"
}
}
]
}
}
}
As for why ins doesn't work, it depends on your mapping + analyzer being used. You are matching against analyzed terms in the index, if you want to match against ins you need to change your analyzer (possibly using the ngram tokenizer) or use a wildcard query.

How to use multi-match query to get half search terms?

I want to find names that start or have the phrase man in them. But I also want to query on different indexes.
So it should return all fields that have the term man in them such as hoffman last name, or anything that has the term in it.
How can I achieve this?
"query": {
"multi_match": {
"query": "man",
"fields": [
"name",
"last_name",
"email"
]
}
}
}
{
"query": {
"multi_match": {
"query": "man",
"fields": [
"billing.name",
"billing.last_name",
"billing.email"
]
}
}
}
If you want to search across multiple indexes, then you can use _index field, and for searching across multiple fields you can use query_String instead of a multi-match query.
GET /_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"_index": [
"index-1",
"index-2"
]
}
},
{
"query_string": {
"query": "*man*"
}
}
]
}
}
}

Elasticsearch with grouped query_string

{
"query":
{
"query_string" :
{
"query" : "((name:the_search_phrase) OR (keywords:the_search_phrase)) AND (city:Sydney, Australia)"
}
}
}
New to elasticsearch. Building the JSON as per the documentation here: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
The query runs, however, results with city other that Sydney, Australia are returned too. Why the AND part is not working?
I want the search phrase to match against either or both name, keywords but the city should be strictly Sydney.
What you are doing is a full text query. city:Sydney, Australia seems to be a filter query. Like a WHERE clause in a SQL. You are better off using a filter query for that.
Look at the boolean query for examples,
Something like this perhaps,
{
"query": {
"bool": {
"must": [
{
"query_string": {
"query": "the_search_term",
"fields": [
"name",
"keywords"
]
}
}
],
"filter": [
{
"match": {
"city": "Sydney, Australia"
}
}
]
}
}
}

Elasticsearch filter with multi_match

I'm trying to write a query in ElasticSearch where I combine multi_match with filter for an id or a number og ids.
This is what i have so far:
{
"query": {
"bool": {
"must": {
"multi_match": {
"query": "Kasper",
"fields": ["name", "first_name", "last_name"]
}
},
"filter": {
"term": {
"user_id": "ea7528f0-1b8a-11e8-a492-13e39bbd17cb"
}
}
}
}
}
The "must" part of the query works perfectly, and when I run it alone, I get two results.
When I pick out the "user_id" from one of the two results and adds the "filter" part of the query with that id, I get nothing.
What I really want to do is have something like in SQL where user_id in ('id1', 'id2'), so the filtering would be something like:
...,
"filter": {
"terms": {
"user_id": ["ea7528f0-1b8a-11e8-a492-13e39bbd17cb"]
}
}
Did I misunderstand something here?
I'm guessing that this is because user_id field is treated as a text and is analyzed. You should use keyword type in this situation (you need just change the mapping of user_id field.
Another way (if you are on Elasticsearch 5+) you can search in keyword subfield. Just try use below query:
{
"query": {
"bool": {
"must": {
"multi_match": {
"query": "Kasper",
"fields": ["name", "first_name", "last_name"]
}
},
"filter": {
"term": {
"user_id.keyword": "ea7528f0-1b8a-11e8-a492-13e39bbd17cb"
}
}
}
}
}
I only changed "user_id" to "user_id.keyword" in your query.

Resources