How can you sort documents by nested object in elastic search using go? - elasticsearch

I'm new to Elasticsearch.
I have documents and each of them has a structure like this:
{
"created_at": "2018-01-01 01:01:01",
"student": {
"first_name": "john",
"last_name": "doe"
},
"parent": {
"first_name": "susan",
"last_name": "smile"
}
}
I just want to sort those documents based on student.first_name using olivere/elastic package for go.
This is my query at the moment:
searchSvc = searchSvc.SortBy(elastic.NewFieldSort("student.first_name").Asc())
and I'm getting this error:
elastic: Error 400 (Bad Request): all shards failed
[type=search_phase_execution_exception]
However when I tried sorting it by created_at, it's working.
searchSvc = searchSvc.SortBy(elastic.NewFieldSort("created_at").Asc())
I don't have any mapping in the index. (is this the problem?)
I tried searching for something like "Elasticsearch sort by nested object", but I always got questions that need to sort an array in the nested object.

It turns out that this is a beginner mistake.. You can't sort by text fields. I got it from here elasticsearch-dsl-py Sorting by Text() field
What you can do though, if you don't specify mappings, you can sort by the keyword property of the field.
searchSvc = searchSvc.SortBy(elastic.NewFieldSort("student.first_name.keyword").Asc())
And it works!

Related

How to make _source field dynamic in elasticsearch search template?

While using search query in elastic search we define what fields we required in the response
"_source": ["name", "age"]
And while working with search templates we have to set _source fields value while inserting search template to ES Cluster.
"_source": ["name", "age"]
but the problem with the search template is that it will always return us name and age and to get other fields we have to change our search template accordingly.
Is there any way we can pass search fields from the client so that it will only return fields in response to which the user asked?
I have achieved that just for one field like if you do this
"_source": "{{field}}"
then while search index via template you can do this
POST index_name/_search/template
{
"id": template_id,
"params": {
"field": "name"
}
}
This search query returning the name field in response but I could not find a way to pass it as in array or in another format so I can get multiple fields.
Absolutely!!
Your search template should look like this:
"_source": {{#toJson}}fields{{/toJson}}
And then you can call it like this:
POST index_name/_search/template
{
"id": template_id,
"params": {
"fields": ["name"]
}
}
What it's going to do is to transform the params.fields array into JSON and so the generated query will look like this:
"_source": ["name"]

Error when trying to rename a nested object name in elasticsearch

I'm trying to rename data that is in this shape:
using this:
POST r_xair_signals-2020-06/_update/2020-06-15T22:23:00Z_-1344027716
{
"doc" : {
"Customer ImpactedNested" : "CustomerImpactedNested"
}
}
But I'm getting:
"type": "mapper_parsing_exception",
"reason": "object mapping for [Customer ImpactedNested] tried to parse field [Customer ImpactedNested] as object, but found a concrete value"
I've confirmed the type of Customer ImpactedNested is nested. I see info online about people getting this error, but not when trying to rename, and don't see any solutions. I saw one article that indicated it occurred when the new name conflicted with an existing name. So, tried renaming to CustomerImpactedNested11111 as a test (sure to be unique), but same result.
Any ideas would be great!
There are two problems actually.
Your query is not renaming the field.
Renaming the nested field
What is happening actually in the following line from the question:
POST r_xair_signals-2020-06/_update/2020-06-15T22:23:00Z_-1344027716
{
"doc" : {
"Customer ImpactedNested" : "CustomerImpactedNested"
}
}
It updates column value of column=Customer ImpactedNested to CustomerImpactedNested document whose id is 2020-06-15T22:23:00Z_-1344027716.
And Customer ImpactedNested is a nested object and you are trying to set a string value to the nested object field. Hence you are getting the error. Refer this
Coming to your original problem, you need to do this via reindex. Refer this, this also
POST _reindex
{
"source": {
"index": "r_xair_signals-2020-06"
},
"dest": {
"index": "<some_new_index_name>"
},
"script": {
"inline": """ctx._source['CustomerImpactedNested'] = ctx._source.remove("Customer ImpactedNested")"""
}
}
Please try the above and let me know for errors as I didn't try the above query.

Elasticsearch nested objects with query_string as first class attributes

I'm trying to index a nested field as a first-class attribute in my document so that I can search them using query_string without dot syntax.
For example, if I have a document like
"data": { "name": "Bob" }
instead of searching for data.name:Bob I would like to be able to search for name:Bob
The root of my issue is that we index a jsonb column that may have varying attributes. In some instances the data property may contain a data.business attribute, etc. I would like users to be able to search on these attributes without needing to "dig" into the object.
The data field does not have to be indexed as a nested type unless necessary; I was indexing it as an object previously.
I have tried to leverage the _all field as suggested in this post.
I have also tried to use include_in_parent:true and set the datatype as nested for my data field as suggested in this post.
I have also looked into the inner_hits feature to no avail.
Here's an example of my mapping for the data attribute.
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"data": {
"type": "object"
}
}
}
}
}
Example document
PUT my_index/_doc/1
{
"data": {
name: "bob",
business: "None of yours"
}
}
And how my query currently looks:
GET my_index/_search
{
"query": {
"query_string": {
"query": "name:bob",
"fields": ["data.*"]
}
}
}
With the current setup I almost get my desired results. I can search on individual properties like data.name:bob and data.business:"None of yours" and get back the correct documents.
However I want to be able to get the exact same results with business:"None of yours" or name:bob.
Thanks in advance for any help!
I figured it out using dynamic templates. For anyone coming across this in the future, here is how I solved the issue:
I used path_match to match the data object (data.*).
Then using copy_to and {name} I dynamically created top-level fields on my parent object.
{
"dynamic_templates":[
{"template_1":
{"mapping":
{"copy_to":"{name}"},
"path_match":"data.*"
}
}
]
}

Elasticsearch: querying on both nested object properties and parent properties

I have some documents which have nested objects inside nested objects :
{
"started_at": 1455088063966,
"ended_at": 1455088131966,
"tags": [{
"type": "transfer",
"at": 1455088064462,
"events": [{
"type": "transfer_processed",
"at": 1455088131981
}]
}, {
"at": 1455088138232,
"item": "tag",
"type": "info"
}]
}
Here, the main document has several nested objects (the tags), and for each tag there are several nested objects (the events).
I would like to get all the documents where the events of type transfer_processed occured 60000 milliseconds after the tags of type transfer.
For this, I would need to query on both tags.at, tags.type, tags.events.at and tags.events.type. And I can't figure out how: I only manage to query on the tags.events properties, or only on the tags properties, not both.
Nested objects are actually separate Lucene documents under the hood, so you are essentially trying to "join" multiple documents together to do your comparisons. Unfortunately, this is not supported by Elasticsearch.
Have a look at this similar question and answer which explain it well.

Find matching array items in MongoDB document

I am developing a web app using Codeigniter and MongoDB.
In the database I got a document that look like this:
{
"_id": {
"$id": "4f609932615a935c18r000000"
},
"basic": {
"name": "The project"
},
"members": [
{
"user_name": "john",
"role": "user",
"created_at": {
"sec": 1331730738,
"usec": 810000
}
},
{
"user_name": "markus",
"role": "user",
"created_at": {
"sec": 1331730738,
"usec": 810000
}
}
]
}
I need to search this document using both user_name and role. Right now when I am using the below code I get both. I only want to get array items matching both user_name and role.
$where = array (
'_id' => new MongoId ($account_id),
'members.user_id' => new MongoId ($user_id),
'members.role' => $role
);
$this -> cimongo -> where ($where) -> count_all_results ('accounts');
This is an old question, but as of MongoDB 2.2 or so you can use the $ positional operator in a projection so that only the matched array element is included in the result.
So you can do something like this:
$this->cimongo->where($where)->select(array('members.$'))->get('accounts');
This is a repeat of this question:
Get particular element from mongoDB array
Also you might want to use $elemMatch
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray
Here is the rub -- you aren't going to be able to get the array items that match because mongo is going to return the entire document if those elements match. You will have to parse out the code client side. Mongo doesn't have a way to answer, "return only the array that matches."

Resources