How to update child document in Elastic search using update API? - elasticsearch

I use parent-child documents in Elastic Search. I can do partial updates of the master document using the _update api. However, if I use the _update APi on a child document, the content of the document is completely replaced by the content of my script. Something goes wrong ... and I do not know what ....
See example below:
CREATE CHILD DOCUMENT
POST to /indexName/comment/c006?parent=b003
{
"authorId": "ps101",
"authorFullName": "Lieven",
"body": "Comment text comes here",
"isApproved": false
}
GET CHILD
GET to /indexName/comment/c006?parent=b003
{
_index: "indexName"
_type: "comment"
_id: "c006"
_version: 20
found: true
-_source: {
authorId: "ps101"
authorFullName: "Lieven"
body: "Comment text comes here."
isApproved: false
}
}
PARTIAL UPDATE
POST TO /indexName/comment/c006?parent=b003/_update
{
"script" : "ctx._source.isAcceptedAnswer=value",
"params" : {
"value" : true
}
}
NOW, GET AGAIN THE CHILD
GET to /indexName/comment/c006?parent=b003
{
_index: "indexName"
_type: "comment"
_id: "c006"
_version: 21
found: true
-_source: {
script: "ctx._source.isAcceptedAnswer=value"
-params: {
value: true
}
}
}
Source is completely wrong ...
Hope somebody can help
Marc

Change
POST TO /indexName/comment/c006?parent=b003/_update
to
POST TO /indexName/comment/c006/_update?parent=b003
The ? is the beginning of the query string, and it goes on the end.

Related

Update restrictions on Elasticsearch Object type field

I have to store documents with a single field contains a single Json object. this object has a variable depth and variable schema.
I config a mapping like this:
"mappings": {
"properties": {
"#timestamp": {
"type": "date"
},
"message": {
"type": "object"
}
}
}
It works fine and Elasticsearch creates and updates mapping with documents that received.
The problem is that after some updates in mapping, it rejects new documents and do not update mapping anymore. At this time I change the indices and mapping update occurred for that indies. I'm looking forward to know the right solution.
for example the first document is:
{
personalInfo:{
fistName: "tom"
}
moviesStatistics: {
count: 100
}
}
the second document that will update Elasticsearch mapping is:
{
personalInfo:{
fistName: "tom",
lastName: "hanks"
},
moviesStatistics: {
count: 100
},
education: {
title: "a title..."
}
}
Elasticsearch creates mapping with doc1 and updates it with doc2, doc3, ... until a number of documents received. After that it starts to reject every document that is not matched to the last mapping fields.
After all I found the solution in the home page of Elasticsearch https://www.elastic.co/guide/en/elasticsearch/reference/7.13//dynamic-field-mapping.html
We can use Dynamic mapping and simply use this mapping:
"mappings": {
"dynamic": "true"
}
You should also change some default restrictions that mentioned here:
https://www.elastic.co/guide/en/elasticsearch/reference/7.13//mapping-settings-limit.html

Retrieve contents of _source only- Elasticsearch ( Node JS)

According to Retrieving a document documentation
GET /website/blog/123/_source
would directly return the document stored inside the _source field.
I'm currently using Node JS's express framework. How should I implement this in my code?
esClient.search({
index: "myIndex",
type: "myType",
body: {
"query": {
"match_all": {}
},
"size": 3,
"from": 1
}
}).then(function (resp) {
var result = resp.hits.hits;
res.status(200).send({data: {recommendations: result, showItemFrom: showItemFrom}})
}, function (err) {
console.trace(err.message)
res.status(500).send({data: err.message})
})
I'm getting the response this way...
[
"_source":{
{
"id": 1,
"title": "Test"
}
}
]
However, I want it this way...
[
{
id:1,
title:"Test"
}
]
I don't think the Elasticsearch API has a method to do that for searches, the one that Val mentioned works, but it is only usable to GET documents directly through its id.
But you can map the result using the Javascript Array#map() method:
var result = resp.hits.hits.map(hit => hit._source);
After
index:"myIndex"
Add:
source:true
You need to call the getSource() function, like this:
esClient.getSource({
index: "website",
type: "blog",
id: "123"
}).then(function (source) {
// do something with source
}, function (err) {
// error happened
})

ElasticSearch Query with two fields and 'AND' filter - Java API

Let's say I have a index in elasticsearch with two fields: title and tags. I have few documents there
Should be returned by query
{ title: "My main title on this page", tags: ["first", "whatever"] }
Should not be returned by query
{ title: "My on this page", tags: ["first", "page", "whatever"] }
Should be returned by query
{ title: "My main title on this page", tags: ["page", "whatever"]}
I want to find all documents which title CONTAINS "main title" AND tag "first" OR "page".
I want to use java API for this, but I'm not sure how can I do this. I know that I can use filter query to create "or" and "and". Not sure how can I add to query the title part, and how can I get the logic with "at least one from the list".
Any ideas?
It depends whether you care about the order of the "main" and "title" words (is it a phrase), but this is relatively simple:
{
"query" : {
"bool" : {
"must" : [
{
"match_phrase" : {
"title" : "main title"
}
},
{
"terms" : {
"tags" : [ "first", "page" ]
}
}
]
}
}
}
By default, the terms query is going to work as a single match and it will boost the score (relevancy) by matching multiple tags. This will perform an exact match, which you should only do with not_analyzed strings. Anything with in the must will inherently behave like an AND; you can understand the bool query/filter by checking here. This translates pretty simply into the Java API:
import static org.elasticsearch.index.query.QueryBuilders.*;
SearchResponse response =
client.prepareSearch("your-index").setTypes("your-type")
.setQuery(
boolQuery()
.must(matchPhraseQuery("title", "main title"))
.must(termsQuery("tags", "first", "page"))
.execute()
.actionGet();

elasticsearch - how to query relations

I have the currenct structure:
localhost:9200/objects/content
{
id:1,
author:{
name:"john"
},
body:"abc"
}
localhost:9200/objects/reaction
{
content_id:1
message:'I like it'
}
How can I query to get all reactions of contents writed by "john"?
This means a query on reactions, checking the content specified by id, if author is "someone".
This Elasticsearch blog post describes how to manage relationships inside Elasticsearch.
You will need to set a parent mapping between your reactions and your content.
{
"reaction" : {
"_parent" : {
"type" : "content"
}
}
}
You will then index your reaction as a child of content id 1:
curl -XPOST localhost:9200/test/homes?parent=1 -d'
{
message:'I like it'
}
You can then use a Has Parent Query to retrieve all reactions to authors named john:
{
"has_parent" : {
"parent_type" : "content",
"query" : {
"term" : {
"author.name" : "john"
}
}
}
}
I would recommend you to add some redundancy to your model:
localhost:9200/objects/reaction
{
content_id:1
message:'I like it'
author_name:'john'
}
This will increase the index, of course. On the other hand the query to get all reactions of contents writed by "john" will be simple and fast.

Check for id existence in param Array with Elasticsearch custom script field

Is it possible to add a custom script field that is a Boolean and returns true if the document's id exists in an array that is sent as a param?
Something like this https://gist.github.com/2437370
What would be the correct way to do this with mvel?
Update:
Having trouble getting it to work as specified in Imotov's answer.
Mapping:
Sort:
:sort=>{:_script=>{:script=>"return friends_visits_ids.contains(_fields._id.value)", :type=>"string", :params=>{:friends_visits_ids=>["4f8d425366eaa71471000011"]}, :order=>"asc"}}}
place: {
properties: {
_id: { index: "not_analyzed", store: "yes" },
}
}
I don't get any errors, the documents just doesn't get sorted right.
Update 2
Oh, and I do get this back on the documents:
"sort"=>["false"]
You were on the right track. It just might be more efficient to store list of ids in a map instead of an array if this list is large.
"sort" : {
"_script" : {
"script" : "return friends_visits_ids.containsKey(_fields._id.value)",
"type" : "string",
"params": {
"friends_visits_ids": { "1" : {}, "2" : {}, "4" : {}}
}
}
}
Make sure that id field is stored. Otherwise _fields._id.value will return null for all records.

Resources