Is it possible to combine _msearch and a suggester in Elasticsearch? - elasticsearch

I'm trying to bundle multi search api with a term suggester.
When I try to use a suggester on the search endpoint, it works:
POST my-index-000001/_search
{
"query" : {
"match": {
"message": "tring out Elasticsearch"
}
},
"suggest" : {
"my-suggestion" : {
"text" : "tring out Elasticsearch",
"term" : {
"field" : "message"
}
}
}
}
Here's how to try to do the same with multi search:
GET my-index-000001/_msearch
{ }
{
"query" : {
"match": {
"message": "tring out Elasticsearch"
}
},
"suggest" : {
"my-suggestion" : {
"text" : "tring out Elasticsearch",
"term" : {
"field" : "message"
}
}
}
}
{"index": "my-index-000002"}
{"query" : {"match_all" : {}}}
As a result, I get an error:
{
"error" : {
"root_cause" : [
{
"type" : "json_e_o_f_exception",
"reason" : "Unexpected end-of-input: expected close marker for Object (start marker at [Source: (org.elasticsearch.common.bytes.AbstractBytesReference$MarkSupportingStreamInputWrapper); line: 1, column: 1])\n at [Source: (org.elasticsearch.common.bytes.AbstractBytesReference$MarkSupportingStreamInputWrapper); line: 1, column: 2]"
}
],
"type" : "json_e_o_f_exception",
"reason" : "Unexpected end-of-input: expected close marker for Object (start marker at [Source: (org.elasticsearch.common.bytes.AbstractBytesReference$MarkSupportingStreamInputWrapper); line: 1, column: 1])\n at [Source: (org.elasticsearch.common.bytes.AbstractBytesReference$MarkSupportingStreamInputWrapper); line: 1, column: 2]"
},
"status" : 400
}
So my question is, is it even possible?
I found a similarly named question (Using Nest Phrase Suggester on MultiSearch query), but the question itself appears to be about multi-match queries, not multi search.
The version I'm using is 7.13.

Your queries are syntactically correct but the Multi Search API (_msearch) only supports newline-delimited json payloads (ndjson).
As such, line breaks (\n) can only occur when separating the payload header from the payload body:
header\n
body\n
header\n
body\n
...
So, adjust your line breaks to conform with the required structure:
GET my-index-000001/_msearch
{}
{"query":{"match":{"message":"tring out Elasticsearch"}},"suggest":{"my-suggestion":{"text":"tring out Elasticsearch","term":{"field":"message"}}}}
{"index":"my-index-000002"}
{"query":{"match_all":{}}}
Tip: if you're using Kibana (and it looks like you are), you can toggle between the expanded and the _msearch-valid mode with ⌘+i / ctrl+i.

Related

ES curl for email is not returning correct results despite knowing that it does exist

I do a query for a term "owner" and a document showed the email for an owner. I figured to look at all Houses which have this email, to query for email instead of owner.
When I do the following curl request, It doesnt return any actual cases.
curl -X GET "localhost:9200/_search/?pretty" -H "Content-Type: application/json" -d'{"query": {"match": {"email": {"query": "test.user#gmail.com"}}}}'
it does not return the correct information. I wanted to find an exact result. I was also thinking to use the term:
curl -X GET "localhost:9200/_search/?pretty" -H "Content-Type: application/json" -d'{"query": {"term": {"email": "test.user#gmail.com"}}}'
in an attempt to find an exact match. This seems to return no document information. I am thinking that it might have something to do with the periods or maybe the # symbol.
I have also tried match when trying to wrap the email with escaped quotes, escaped periods.
Is there something going on I am unaware of with special characters?
Elasticsearch is not schema free, now they are calling it "schema on write" and that´s a very good name for the schema generation process. When elasticsearch recieves a new document with unknown fields, it tries an "educated guess".
When you index the first document with the field "email", elasticsearch will have a look on the value provided and create a mapping for this field.
The value "test.user#gmail.com" will then be mapped to "Text" mapping type.
Now, let´s see how elastic will process a simple document with a email. Create a document:
POST /auto_mapped_index/_doc
{"email": "nobody#example.com"}
Courious how the mapping look like? Here you go:
GET /auto_mapped_index/_mapping
Will be answered with:
{
"my_first_index" : {
"mappings" : {
"properties" : {
"email" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
You see, the "type" : "text" is indicating the mapping type "text" as assumed before. And there is also a subfield "keyword", automatically created by elastic for text type fields by default.
We have 2 options now, the easy one is to query the keyword subfield (please note the dot notation):
GET /my_first_index/_search
{"query": {"term": {"email.keyword": "nobody#example.com"}}}
Done!
The other option is to create a specific mapping for our index. In order to do so, we need a new and empty index and define the mapping. We can do it with one shot:
PUT /my_second_index/
{
"mappings" : {
"properties" : {
"email" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
Now let us populate the index (here i´m putting two documents):
POST /my_second_index/_doc
{"email": "nobody#example.com"}
POST /my_second_index/_doc
{"email": "anybody#example.com"}
And now your unchanged query should work :
GET /my_second_index/_search
{"query": {"term": {"email": "anybody#example.com"}}}
Response:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "my_second_index",
"_type" : "_doc",
"_id" : "OTf3n28BpmGM8iQdGR4j",
"_score" : 0.2876821,
"_source" : {
"email" : "anybody#example.com"
}
}
]
}
}

elasticsearch percolator filter fails

I'm using a document query against a percolator that works ok. When I try to filter the percolator queries against which document percolate using queries ids, it doesn't return any result. For example:
{
"doc" : {
"text" : "This is the text within my document"
},
"highlight" : {
"order" : "score",
"pre_tags" : ["<example>"],
"post_tags" : ["</example>"],
"fields" : {
"text" : { "number_of_fragments" : 0 }
}
},
"filter":{"ids":{"values":[11,15]}}
,
"size" : 100
}
I know for sure that those ids are correct, but allways obtain "matches" : [ ]. When I don't use filter, ES retrieves correct matches.
Thanks for your help.
I think I've solved it. It seems that the filter only works on the "metadata" fields, meaning that you have to add customized fields to the queries indexed in the percolator in order to use them to filter when you need.
Using my previous example, I would have to index in percolator queries like:
{
"query" : {
"match_phrase" : {
"text" : "document"
}
},
"id" : 11
}
Adding "manually" a redundant id field in order to use it later as filter reference.
At percolation time, you have to use something like:
{
"doc" : {
"text" : "This is the text within my document"
},
"filter":{"match":{"id":11}},
"highlight" : {
"order" : "score",
"pre_tags" : ["<example>"],
"post_tags" : ["</example>"],
"fields" : {
"text" : { "number_of_fragments" : 0 }
}
},
"size" : 100
}
In order to use only that percolator query. Complementary information can be found here.

Elasticsearch does not found an existing document using a the DSL

I dont know why, using the URI Search way to search a document is returning the right document, but the document is not found if I use the API DSL.
To reproduce the issue:
Without any index created, I insert this document:
curl http://localhost:9299/integrationtest-index/searchable/ID_XXXX2 -d '{ "ref" : "XXXX2", "field1" : "value1" }'
So the index is created automatically with the default mapping (type searchable):
curl http://localhost:9299/integrationtest-index?pretty
{
"integrationtest-index" : {
"aliases" : { },
"mappings" : {
"searchable" : {
"properties" : {
"field1" : {
"type" : "string"
},
"ref" : {
"type" : "string"
}
}
}
},
"settings" : {
"index" : {
"field1" : "value1",
"ref" : "XXXX2",
"number_of_shards" : "5",
"creation_date" : "1466780216631",
"number_of_replicas" : "1",
"uuid" : "GBj2VF-wQy6JP74AqoIn5g",
"version" : {
"created" : "2020099"
}
}
},
"warmers" : { }
}
}
This query return one document:
curl http://localhost:9299/integrationtest-index/searchable/_search?q=ref:XXXX2
But this other query response that does not exist:
curl -XPOST http://localhost:9299/integrationtest-index/searchable/_search/exists -d '
{
"query": {
"term" : {
"ref" : "XXXX2"
}
}
}'
Why the last query said that the document does not exist?
Environment:
ElasticSearch 2.2.0
Ubuntu 16.04 LTS
OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-0ubuntu4~16.04.1-b14)
I have the same problem every few months, so I decided response myself and share my stupids errors.
By default, elasticsearch use index:analyzed, so the query with term does not found any document.
If you use the URI Search way, elasticsearch is executing a query_string and not a term query.
This query is working:
curl -XPOST http://localhost:9299/integrationtest-index/searchable/_search/exists -d '
{
"query": {
"match" : {
"ref" : "XXXX2"
}
}
}'
More information in the documentation, in the section Why doesn’t the term query match my document?

Elasticsearch - "OR" query condition using match query and term query

I have following match query string:
curl -XGET 'my-es.com/my_indice/_search?pretty' -d '{
"size" : 10,
"query" : {
"bool" : {
"must" : [ {
"match" : {
"state" : {
"query" : ["ACTIVE", "INACTIVE"],
"type" : "boolean"
}
}
}]
}
}
}'
I guess it means "state" = "ACTIVE" or "state" = "INACTIVE", but actually it performs "state" = "INACTIVE".
Then I tried term query string:
curl -XGET 'my-es.com/my_indice/_search?pretty' -d '{
"size" : 10,
"query" : {
"bool" : {
"must" : [{
"terms" : { "state" : ["ACTIVE", "INACTIVE"] }
}]
}
}
}'
It performs "state" = "ACTIVE" or "state" = "INACTIVE", showing term query supports multiple OR conditions via an array.
I'm curious about why match query does not support OR condition via an array? And it does not show any syntax error.
The match query only supports a single string value to be specified. It is not explicitly specified in the official match documentation, but if you're willing to read some source code for MatchQueryParser.java, you can see that while parsing the query field, the parser will skip the tokens delimiting the start and end of the array and always override the value with the latest one being parsed, hence why you're seeing what you see, i.e. that state will be matched with INACTIVE only.
What you can do, however, is to put both tokens inside the same string like below, and both tokens will be taken into account:
curl -XGET 'my-es.com/my_indice/_search?pretty' -d '{
"size" : 10,
"query" : {
"bool" : {
"must" : [ {
"match" : {
"state" : {
"query" : "ACTIVE INACTIVE",
"type" : "boolean"
}
}
}]
}
}
}'

Unable to update mapping in elastic search

I have a shell script to create a mapping to one of my document types in elastic search.
My elasticsearch index is bits and my document type is nts and I am trying to assign type long for 3 JSON keys in the document of type nts
namely NT, XT and YT.
#!/bin/bash
curl -XPUT 'http://localhost:9200/bits/nts/_mapping' -d '
{
"events" : {
"dynamic" : "strict",
"properties" : {
"NT" : {
type : "long"
},
"XT" : {
type : "long"
},
"YT" : {
type : "long"
}
}
},
}'
If I run the above bash script, I get the following error.
{"error":"ElasticsearchParseException[Failed to parse content to map]; nested: JsonParseException[Unexpected character ('}' (code 125)): was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name\n at [Source: org.elasticsearch.common.compress.lzf.LZFCompressedStreamInput#6d7702cc; line: 17, column: 6]]; ","status":400}
Remove the last comma and make the code like this
curl -XPUT 'http://localhost:9200/bits/nts/_mapping' -d '
{
"events" : {
"dynamic" : "strict",
"properties" : {
"NT" : {
type : "long"
},
"XT" : {
type : "long"
},
"YT" : {
type : "long"
}
}
}
}'

Resources