Is there any way not to return arrays when specifying return fields in an Elasticsearch query? - elasticsearch

If I have a documents like this :
[
{
"model": "iPhone",
"brand": "Apple"
},
{
"model": "Nexus 5",
"brand": "Google"
}
]
And that I make a query which only returns the model field in a query, like this:
{
"fields": ["model"],
"query": {
"term": {
"brand": "apple"
}
}
}
Then each document field is returned within an array like this:
{ "model": ["iPhone"] }
instead of
{ "model": "iPhone" }
How can I avoid that and get the fields in the same format as when the fields query option is not defined?

At the end the answer was pretty easy: you have to use the _source query option insteand of fields.
Example:
{
"_source": ["model"],
"query": {
"term": {
"brand": "apple"
}
}
}
This way I get documents in the following format, like in the original one (without the _source option):
{ "model": "iPhone" }

I had the same problem, and indeed (as Wax Cage said) I thought that _source would bring some performances problems. I think using both fields and _source solves the problem:
const fields = ['model']
{
fields: fields,
_source: fields
query: {
term: {
brand: 'apple'
}
}
}

Related

Retrieve documents based on an element inside an array in each document

I am working on an elastic query which need to return all the documents based on an attribute which is inside the first element in an array in the document. Please refer the document structure below.
User document
{
"name": "Sam",
"age": 20,
"vehicle": [
{
"type": "car",
"capacity": 4,
"registration": {
"date": "20.02.2020",
"plate": null
}
}
]
}
Every document only having 1 element in vehicle array.
Above is a sample document in my ES and the requirement is to get all the documents which has "null" value for plate attribute (similar to the example) in collection. I have tried various queries for two days but non of them got succeeded and got errors in query. What's the solution to this?
My suggestion is check any field exists inside field "vehicle" for example: field "type".
{
"query": {
"nested": {
"path": "vehicle",
"query": {
"bool": {
"must_not": [
{
"exists": {
"field": "vehicle.registration.plate"
}
}
]
}
}
}
}
}

How to match first and last names with Elasticsearch?

A typical Elasticsearch JSON response is kind of like:
[
{
"_index": "articles",
"_id": "993",
"_score": 10.443843,
"_source": {
"title": "This is a test title",
"authors": [
{
first_name: 'john',
last_name: 'smith'
},
How can I query for all articles where one of the authors is 'john smith'? Currently I have:
const {
hits: { hits }
} = await client.search({
index: "articles",
body: {
query: {
bool: {
should: [
{
match: {
"authors.first_name": "john"
}
},
{
match: {
"authors.first_name": "Smith"
}
}
]
}
}
}
});
But this returns articles where first or last name are john or smith, not articles with a 'john smith' as an author.
I think you are facing nested vs. object dilemma here. You can achieve what you are looking for by changing the type of authors field to nested type (you didn't share your index mapping so I'm assuming here) and using this query
{
"query":{
"nested":{
"path":"authors",
"query":{
"bool":{
"must":[
{
"match":{
"authors.firstName":{
"query":"john"
}
}
},
{
"match":{
"authors.lastName":{
"query":"Smith"
}
}
}
]
}
}
}
}
}
Hope that helps.
Well in this case your using a "should" statement which can be explained as
firstname:john OR lastname:smith
this can be easily fix with a "must" instead, which can be explained as
firstname:john AND lastname:smith
Also as rob mention in his response, nested vs object is indeed a dilema.
but this dilema would appear when you're treating with arrays of information.
for example you have the following entry
entry #1
{
"serviceType": "mysql",
"allowedUsers": [
{
"firstName": "Daniel",
"lastName": "Acevedo"
},
{
"firstName": "John",
"lastName": "Smith"
},
{
"firstName": "Mike",
"lastName": "K"
}
]
}
and you do the following search
{
"size": 10,
"query": {
"query_string": {
"query": "allowedUsers.firstName:john AND allowedUsers.lastName:acevedo"
}
}
}
you WILL have a match in the document because because both firstName and lastName match your document even though they match in different user objects. this is an example of OBJECT mapping.
in this case there is no work around, and you must use NESTED mapping in order to acomplish a natural match.
in your specific case i dont think you're facing this so going with OBJECT and MUST (AND instead of should (OR)) query you should do fine.
if you need further explanation let me know I'll make an edit with more details.
cheers.

multi_match fuzzy query across multiple fields

I am working to match a 'term' to multi fields (or _all field)
I want to do a fuzzy match on cross_fields but it is not supported.
any ideas how to do it or any other ways to do it ?
query: {
multi_match: {
query: term,
type: "cross_fields",
fields: ['_all']
}
}
when trying the solution here
ElasticSearch multi_match query over multiple fields with Fuzziness
I get this error
[parsing_exception] Fuziness not allowed for type [cross_fields], with
{ line=1 & col=128 }
elasticsearch version 5.0
edit:
here is the query I am building
bool: {
must: [
{
fuzzy: {
_all: term
}
},
{
fuzzy: {
"location.country": country
}
},
{
fuzzy: {
"location.city": city
}
}
]
}
cross_fields works by searching the term on your multiple fields. Since fuzziness isn't supported for cross_fields you have to write the query in a different way.
One possible is: implement your own "cross_fields" with shoulds and add there the fuzziness.
Say your term is: "term1 term2", you can split by word boundary (Regex \b) then should them in this form:
{
{
"query": {
"bool": {
"should": [{
"match": {
"field1": "term",
"fuzziness": 1
}
},{
"match": {
"field1": "term",
"fuzziness": 1
}
},{
"match": {
"field2": "term1",
"fuzziness": 1
}
},{
"match": {
"field2": "term12",
"fuzziness": 1
}
}
]
}
}
}
}
This is probably less the optimal if you have many fields, the query will become a cartesian product of the terms and fields.
Important note You're using _all field which is one field. which all other fields are indexed into. Maybe you don't even need cross_fields?

Elasticsearch with AND query in DSL

this drives me crazy. I have no clue why this elastic search do not return me value.
I put values with this:
PUT /customer/person-test/1?pretty
{
"name": "John Doe",
"personId": 153,
"houseHoldId": 6191136,
"quarter": "2016_Q1"
}
PUT /customer/person-test/2?pretty
{
"name": "John Doe",
"personId": 153,
"houseHoldId": 6191136,
"quarter": "2016_Q2"
}
and when I query like this, it do not returns me value:
GET /customer/person-test/_search
{
"query": {
"bool": {
"must" : [
{
"term": {
"name": "John Doe"
}
},
{
"term": {
"quarter": "2016_Q1"
}
}
]
}
}
}
this query i copied from A simple AND query with Elasticsearch
I just want to get the person with "John Doe" AND "2016_Q1", why this did not work?
You should use match instead of term :
GET /customer/person-test/_search
{
"query": {
"bool": {
"must" : [
{
"match": {
"name": "John Doe"
}
},
{
"match": {
"quarter": "2016_Q1"
}
}
]
}
}
}
Explanation
Why doesn’t the term query match my document ?
String fields can be of type text (treated as full text, like the body
of an email), or keyword (treated as exact values, like an email
address or a zip code). Exact values (like numbers, dates, and
keywords) have the exact value specified in the field added to the
inverted index in order to make them searchable.
However, text fields are analyzed. This means that their values are
first passed through an analyzer to produce a list of terms, which are
then added to the inverted index.
There are many ways to analyze text: the default standard analyzer
drops most punctuation, breaks up text into individual words, and
lower cases them. For instance, the standard analyzer would turn the
string “Quick Brown Fox!” into the terms [quick, brown, fox].
This analysis process makes it possible to search for individual words
within a big block of full text.
The term query looks for the exact term in the field’s inverted
index — it doesn’t know anything about the field’s analyzer. This
makes it useful for looking up values in keyword fields, or in numeric
or date fields. When querying full text fields, use the match query
instead, which understands how the field has been analyzed.
...
its not working because of u r using default standard analyzer link for 'name' and 'quarter' .
You have two more options :-
1)change mapping :-
"name": {
"type": "string",
"index": "not_analyzed"
},
"quarter": {
"type": "string",
"index": "not_analyzed"
}
2)try this , lowercase your value since by default standard analyzer use Lower Case Token Filter :-
{
"query": {
"bool": {
"must" : [
{
"term": {
"name": "john_doe"
}
},
{
"term": {
"quarter": "2016_q1"
}
}
]
}
}
}

Finding which nested entry matched an elasticsearch query

Say I'm indexing elasticsearch data like so:
{"entities": {
"type": "firstName",
"value": "Barack",
},
{
"type": "lastName",
"value": "Obama"
}}
I'd like users to be able to add custom attributes, so I don't know every possible value of "type" ahead of time.
My mappings might look like:
typename:
entities:
type: nested
If I do a match query for the text "Obama", with highlighting, is there a way to get back the full nested "entity" which matched? I would like to know if my query for "Obama" matched the firstName or the lastName.
I was able to solve this with inner_hits (thanks Andrei!)
{
"query": {
"nested": {
"query": {
{"match": {"entities.name": "Obama"}}
}
},
"inner_hits": {
"highlight": {
"fields": {
"entities.name": {}
}
}
}
}
}

Resources