ElasticSearch - multi-match with filter - returns no result - elasticsearch

I have a problem. My search result returns zero when I add a filter in my JSON request
{
"body":
{
"query":{
"multi_match":
{
"query":"Joe Jerick Aparments",
"fields":["name","Category","address","description"]}
},
"filter":
{
"source":"Category":"Apartments"
}
}
}
First things first,
Yes, there is already data.
Yes there is no error
Yes there is no misspelled words
Thanks!

{
index: "stores",
type: "stores",
id: "1",
body: {
name: "Joe Jerick Apartments",
Category: "Apartments"
address: "Somewhere down the road",
description: "Best apartment yet!"
}
}
So, I didn't see this in my earlier comment but if the fields you're querying on are nested inside of body (in storage -- not in retrieval) you'll need a nested query to get at the fields listed (I'm not sure if you're describing your mapping or what it looks like on query retrieval for a match_all)
If this is the case you'll need body to be mapped as "nested" and then your query would look something like this.
{
"query": {
"filtered": {
"query": {
"multi_match": {
"query": "Joe Jerick Apartments",
"fields": [
"body.name",
"body.Category",
"body.address",
"body.description"
]
}
},
"filter": {
"term": {
"body.Category": "Apartments"
}
}
}
}
}
Altertively you could re-import your records with a flattened structure
{
"id": "1",
"name": "Joe Jerick Apartments",
"Category": "Apartments",
"address": "Somewhere down the road",
"description": "Best apartment yet!"
}

Try this query instead:
{
"query": {
"filtered": {
"query": {
"multi_match": {
"query": "Joe Jerick Apartments",
"fields": [
"name",
"Category",
"address",
"description"
]
}
},
"filter": {
"term": {
"Category": "Apartments"
}
}
}
}
}

Related

How to boost specific terms in elastic search?

If I have the following mapping:
PUT /book
{
"settings": {},
"mappings": {
"properties": {
"title": {
"type": "text"
},
"author": {
"type": "text"
}
}
}
}
How can i boost specific authors higher than others?
In case of the below example:
PUT /book/_doc/1
{
"title": "car parts",
"author": "john smith"
}
PUT /book/_doc/2
{
"title": "car",
"author": "bob bobby"
}
PUT /book/_doc/3
{
"title": "soap",
"author": "sam sammy"
}
PUT /book/_doc/4
{
"title": "car designs",
"author": "joe walker"
}
GET /book/_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "car" }},
{ "match": { "title": "parts" }}
]
}
}
}
How do I make it so my search will give me books by "joe walker" are at the top of the search results?
One solution is to make use of function_score.
The function_score allows you to modify the score of documents that are retrieved by a query.
From here
Base on your mappings try to run this query for example:
GET book/_search
{
"query": {
"function_score": {
"query": {
"bool": {
"should": [
{
"match": {
"title": "car"
}
},
{
"match": {
"title": "parts"
}
}
]
}
},
"functions": [
{
"filter": {
"match": {
"author": "joe walker"
}
},
"weight": 30
}
],
"max_boost": 30,
"score_mode": "max",
"boost_mode": "multiply"
}
}
}
The query inside function_score is the same should query that you used.
Now we want to take all the results from the query and give more weight (increase the score) to joe walker's books, meaning prioritize its books over the others.
To achieved that we created a function (inside functions) that compute a new score for each document returned by the query filtered by joe walker books.
You can play with the weight and other params.
Hope it helps

Search-as-you-type inside arrays

I am trying to implement a search-as-you-type query inside an array.
This is the structure of the documents:
{
"guid": "6f954d53-df57-47e3-ae9e-cb445bd566d3",
"labels":
[
{
"name": "London",
"lang": "en"
},
{
"name": "Llundain",
"lang": "cy"
},
{
"name": "Lunnainn",
"lang": "gd"
}
]
}
and up to now this is what I came with:
{
"query": {
"multi_match": {
"fields": ["labels.name"],
"query": name,
"type": "phrase_prefix"
}
}
which works exactly as requested.
The problem is that I would like to search also by language.
What I tried is:
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"fields": ["labels.name"],
"query": "london",
"type": "phrase_prefix"
}
},
{
"term": {
"labels.lang": "gd"
}
}
]
}
}
}
but these queries act on separate values of the array.
So, for example, I would like to search only Welsh language (cy). That means that my query that contains the city name should match only values that have "cy" on the "lang" tag.
How do I write this kind of query?
Internally, ElasticSearch flattens nested JSON objects, so it can't correlate the lang and name of a specific element in the labels array. If you want this kind of correlation, you'll need to index your documents differently.
The usual way to do this is to use the nested data type with a matching nested query.
The query would end up looking something like this:
{
"query": {
"nested": {
"path": "labels",
"query": {
"bool": {
"must": [
{
"multi_match": {
"fields": ["labels.name"],
"query": "london",
"type": "phrase_prefix"
}
},
{
"term": {
"labels.lang": "gd"
}
}
]
}
}
}
}
}
But note that you'll need to also specify nested mappings for your labels, e.g.:
"properties": {
"labels": {
"type": "nested",
"properties": {
"name": {
"type": "text"
/* you might want to add other mapping-related configuration here */
},
"lang": {
"type": "keyword"
}
}
}
}
Other ways to do this include:
Indexing each label as a separate document, repeating the guid field
Using parent/child documents
You should use Nested datatype in mapping instead of Object datatype. For detail explanation refer this:
https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html
So, you should define mapping of your field something like this:
{
"properties": {
"labels": {
"type": "nested",
"properties": {
"name": {
"type": "text"
},
"lang": {
"type": "keyword"
}
}
}
}
}
After this you could query using Nested Query as:
{
"query": {
"nested": {
"path": "labels",
"query": {
"bool": {
"must": [
{
"multi_match": {
"fields": ["labels.name"],
"query": "london",
"type": "phrase_prefix"
}
},
{
"term": {
"labels.lang": "gd"
}
}
]
}
}
}
}
}

Elasticsearch Nested More Like This Query

Is it possible to perform a More Like This query (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html) on text inside a nested datatype (https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html)?
The document that I'd like to query (which I have no control over how it is formatted since the data is owned by another party) looks something like this:
{
"communicationType": "Email",
"timestamp": 1497633308917,
"textFields": [
{
"field": "Subject",
"text": "This is the subject of the email"
},
{
"field": "To",
"text": "to-email#domain.com"
},
{
"field": "Body",
"text": "This is the body of the email"
}
]
}
I would like perform a More Like This query on the body of the email. Before, the documents used to look like this:
{
"communicationType": "Email",
"timestamp": 1497633308917,
"textFields": {
"subject": "This is the subject of the email",
"to: "to-email#domain.com",
"body": "This is the body of the email"
}
}
And I was able to perform a More Like This query on the email body like this:
{
"query": {
"more_like_this": {
"fields": ["textFields.body"],
"like": "This is a similar body of an email",
"min_term_freq": 1
},
"bool": {
"filter": [
{ "term": { "communicationType": "Email" } },
{ "range": { "timestamp": { "gte": 1497633300000 } } }
]
}
}
}
But now that data source has been deprecated, I need to be able to perform an equivalent query on the new data source that has the email body in the nested datatype. I only want to compare the text to the "text" fields that have a "header" of "Body".
Is this possible? And if so, how would the query look like? And would there be a major performance hit to perform the query on the nested datatype compared to before on the non-nested document? Even after applying the timestamp and communicationType filters, there will still be tens of millions of documents that each query would need to compare the like text against, so performance matters.
Actually, it turned out to be straightforward to use a More Like This query inside a nested query:
{
"query": {
"bool": {
"must": {
"nested": {
"path": "textFields",
"query": {
"bool": {
"must": {
"more_like_this": {
"fields": ["textFields.text"],
"like_text": "This is a similar body of an email",
"min_term_freq": 1
}
},
"filter": {
"term": { "textFields.field": "Body" }
}
}
}
}
},
"filter": [
{
"term": {
"communicationType": "Email"
}
},
{
"range": {
"timestamp": {
"gte": 1497633300000
}
}
}
]
}
},
"min_score": 2
}

How to search on multiple fields in URI Search

I would like to perform an AND operation in ElasticSearch using the URI Search (q=). How do I do it?
If I have document like:
[{ "name":"Test 1", "pub":"2"}, { "name":"Test 2", "pub":"1"}, { "name":"A", "pub":"1"}]
And I would like to query for documents containing with a name containing "Test" AND where pub equals "1". How do I do that?
Thanks!
Assuming your document looks like this:
{
"my_field": [
{ "name":"Test 1", "pub":"2"},
{ "name":"Test 2", "pub":"1"},
{ "name":"A", "pub":"1"}
]
}
And the mapping of my_field is of type nested similar to this:
{
"mappings": {
"doc_type": {
"properties": {
"my_field": {
"type": "nested",
"properties": {
"name": { "type": "string" },
"pub": {"type": "integer" }
}
}
}
}
}
}
Then you can query your index and get the expected documents with the following nested query:
POST /_search
{
"query": {
"nested": {
"path": "my_field",
"query": {
"bool": {
"filter": [
{
"match": {
"name": "Test"
}
},
{
"match": {
"pub": 1
}
}
]
}
}
}
}
}
Actually you'd need nested fields. The following is a good resource.
https://www.elastic.co/guide/en/elasticsearch/guide/current/nested-objects.html

elasticsearch nested query, i think

I come from a related database background and something like this would be so simple there, but I can't figure this out. I've been trying to learn Elasticsearch for a week or so and I'm trying to figure out what I think is a nested query. Here's some sample data:
PUT /myindex/pets/_mapping
{
"pets": {
"properties": {
"name": {
"type": "string"
},
"pet": {
"type": "nested",
"properties": {
"name": {"type": "string"}
}
}
}
}
}
POST /myindex/pets/
{"pet": {"name": "rosco"}, "name": "sam smith"}
POST /myindex/pets/
{"pet": {"name": "patches"}, "name": "sam smith"}
POST /myindex/pets
{"pet": {"name": "rosco"}, "name": "jack mitchell"}
What would the query look like that only returns documents matching:
owner name is "sam smith"
pet name is "rosco"
I've tried a mixmatch of bool, match, nested, filtered/filter type queries, but I just keep getting errors. Stuff like this stands out in the errors:
nested: ElasticsearchParseException[Expected field name but got START_OBJECT \"nested\"];
Here was the query:
GET /myindex/pets/_search
{
"query": {
"match": {
"name": "sam smith"
},
"nested": {
"path": "pet",
"query": {
"match": {
"pet.name": "rosco"
}
}
}
}
}
I'm beginning to think that I just can't target something this specific due to the relevant nature of Elasticsearch.
Any ideas?
Man, these queries are tricky sometimes... This seems to work:
GET /myindex/pets/_search
{
"query": {
"filtered": {
"query": {
"match": {
"name": "sam smith"
}
},
"filter": {
"nested": {
"path": "pet",
"query": {
"match": {
"pet.name": "rosco"
}
}
}
}
}
}
}

Resources