I am using Java API for CRUD operation on elasticsearch.
I have an typewith a nested field and I want to update this field.
Here is my mapping for the type:
"enduser": {
"properties": {
"location": {
"type": "nested",
"properties":{
"point":{"type":"geo_point"}
}
}
}
}
Of course my enduser type will have other parameters.
Now I want to add this document in my nested field:
"location":{
"name": "London",
"point": "44.5, 5.2"
}
I was searching in documentation on how to update nested document but I couldn't find anything. For example I have in a string the previous JSON obect (let's call this string json). I tried the following code but seems to not working:
params.put("location", json);
client.prepareUpdate(index, ElasticSearchConstants.TYPE_END_USER,id).setScript("ctx._source.location = location").setScriptParams(params).execute().actionGet();
I have got a parsing error from elasticsearch. Anyone knows what I am doing wrong ?
You don't need the script, just update it.
UpdateRequestBuilder br = client.prepareUpdate("index", "enduser", "1");
br.setDoc("{\"location\":{ \"name\": \"london\", \"point\": \"44.5,5.2\" }}".getBytes());
br.execute();
I tried to recreate your situation and i solved it by using an other way the .setScript method.
Your updating request now would looks like :
client.prepareUpdate(index, ElasticSearchConstants.TYPE_END_USER,id).setScript("ctx._source.location =" + json).execute().actionGet()
Hope it will help you.
I am not sure which ES version you were using, but the below solution worked perfectly for me on 2.2.0. I had to store information about named entities for news articles. I guess if you wish to have multiple locations in your case, it would also suit you.
This is the nested object I wanted to update:
"entities" : [
{
"disambiguated" : {
"entitySubTypes" : [],
"disambiguatedName" : "NameX"
},
"frequency" : 1,
"entityType" : "Organization",
"quotations" : ["...", "..."],
"name" : "entityX"
},
{
"disambiguated" : {
"entitySubType" : ["a", "b" ],
"disambiguatedName" : "NameQ"
},
"frequency" : 5,
"entityType" : "secondTypeTest",
"quotations" : [ "...", "..."],
"name" : "entityY"
}
],
and this is the code:
UpdateRequest updateRequest = new UpdateRequest();
updateRequest.index(indexName);
updateRequest.type(mappingName);
updateRequest.id(url); // docID is a url
XContentBuilder jb = XContentFactory.jsonBuilder();
jb.startObject(); // article
jb.startArray("entities"); // multiple entities
for ( /*each namedEntity*/) {
jb.startObject() // entity
.field("name", name)
.field("frequency",n)
.field("entityType", entityType)
.startObject("disambiguated") // disambiguation
.field("disambiguatedName", disambiguatedNameStr)
.field("entitySubTypes", entitySubTypeArray) // multi value field
.endObject() // disambiguation
.field("quotations", quotationsArray) // multi value field
.endObject(); // entity
}
jb.endArray(); // array of nested objects
b.endObject(); // article
updateRequest.doc(jb);
Blblblblblblbl's answer couldn't work for me atm, because scripts are not enabled in our server. I didn't try Bask's answer yet - Alcanzar's gave me a hard time, because I supposedly couldn't formulate the json string correctly that setDoc receives. I was constantly getting errors that either I am using objects instead of fields or vice versa. I also tried wrapping the json string with doc{} as indicated here, but I didn't manage to make it work. As you mentioned it is difficult to understand how to formulate a curl statement at ES's java API.
A simple way to update the arraylist and object value using Java API.
UpdateResponse update = client.prepareUpdate("indexname","type",""+id)
.addScriptParam("param1", arrayvalue)
.addScriptParam("param2", objectvalue)
.setScript("ctx._source.field1=param1;ctx._source.field2=param2").execute()
.actionGet();
arrayvalue-[
{
"text": "stackoverflow",
"datetime": "2010-07-27T05:41:52.763Z",
"obj1": {
"id": 1,
"email": "sa#gmail.com",
"name": "bass"
},
"id": 1,
}
object value -
"obj1": {
"id": 1,
"email": "sa#gmail.com",
"name": "bass"
}
Related
Small java and spring question regarding how to get a specific key value from a very nested json, without having to map back to java pojos please.
I am consuming an api, where the json response is gigantic. The raw response does not fit in a screen.
The response is also very nested. Meaning, it has fields inside fields inside fields... etc
I have no access, no way to modify this API.
Nonetheless, it is a very interesting API, and in this very gigantic payload, very nested, there is always exactly one "the-key-i-need": "the-value-i-need",
Furthermore, there is no way to know in advanced how nested (which layer, which child) and no way to know where will "the-key-i-need": "the-value-i-need", be.
Also, there is no way to map the response back to any POJO, it changes always, the only information, "the-key-i-need": "the-value-i-need", exists, and it is always there.
I am well aware of GSON or fasterxml libraries, that can help map the json string back to existing pojos.
However, in my case, such will not help, since the existing pojo does not exists. the response is always different, the structure, the level of nesting is always different.
My question is, instead of trying to map back to pojos that will always change, and very nested, is there a simpler way, to just use some kind of regex, or something else, to extract the key value, "the-key-i-need": "the-value-i-need", and only this please?
I already tried mapping to all kinds of pojos, and unfortunately the response structure is too dynamic.
Thank you
Since you're using Spring, you very likely already have Jackson FasterXML in you classpath.
Normally, Spring uses the Databind module, which relies on the Streaming module, aka the Core module.
In this case, you want to use Streaming directly, so get the JSON text as a String, and start the parser.
static String getFieldValue(String json, String field) throws JsonParseException, IOException {
JsonFactory factory = new JsonFactory();
try (JsonParser parser = factory.createParser(json)) {
for (JsonToken token; (token = parser.nextToken()) != null; ) {
if (token == JsonToken.FIELD_NAME && parser.getCurrentName().equals(field)) {
token = parser.nextToken();
// check token here if object or array should throw exception instead of returning null
return parser.getValueAsString();
}
}
}
return null; // or throw exception if "not found" shouldn't return null
}
Test
String json = "{ \"A\": { \"B\": [ 5, { \"C\": \"D\" }, true ], \"E\": null, \"F\": 42, \"G\": false }}";
System.out.println("C: " + getFieldValue(json, "C")); // "D"
System.out.println("E: " + getFieldValue(json, "E")); // null (null-value)
System.out.println("F: " + getFieldValue(json, "F")); // "42"
System.out.println("G: " + getFieldValue(json, "G")); // "false"
System.out.println("H: " + getFieldValue(json, "H")); // null (not found)
System.out.println("B: " + getFieldValue(json, "B")); // null (not a value)
JsonPath
If using an external library is an option, then JsonPath might help.
Maven
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.5.0</version>
</dependency>
StackOverflow Tag for JsonPath
Example usage as shared in the README
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century"
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
To access all the author names
List<String> authors = JsonPath.read(json, "$..author");
System.out.println(authors);
Output
["Nigel Rees","Evelyn Waugh"]
To access all the prices (across both book and bicycle)
List<Double> prices = JsonPath.read(json, "$..price");
System.out.println(prices);
Output
[12.99, 19.95]
Note
Some missing keys can cause remapping extracted data across two fields difficult
Say fetching category and price from the above example will make it difficult to summarize a category to price mapping
List<String> categories = JsonPath.read(json, "$..category");
System.out.println(categories);
Output
["reference", "fiction"]
Based on the above example, price and category does not have correct 1-1 mapping
Though I could see this question might be repeated but couldn't find any similar solution for the below JSON strut. Pls suggest.
I have excel sheet where the data's in columns look like :
CSV file data
My expected JSON as:
{
"Child ": {
"10"
: { "Post": { "Kid-R":1 },
"Var": [1,1 ],
"Tar": [2,2],
"Fur": [3,3]},
"11":
{"Post": {"Kid-R":2 },
"Var": [1,1 ],
"Tar": [2,2 ],
"Fur": [5,4 ]}
},
"Clone": [],
"Birth": 2,
"TT": 11,
"Clock": ${__time(/1000,)}
}
I have tried incorporating beanshell preprocessor in JMeter & tried below code:
def builder = new groovy.json.JsonBuilder()
#groovy.transform.Immutable
class Child {
String post
String var
String Tar
String Fur
}
def villas = new File("Audit_27.csv")
.readLines()
.collect { line ->
new child (line.split(",")[1],(line.split(",")
[2]+","+line.split(",")[3]),(line.split(",")[4]+","+line.split(",")
[5]),(line.split(",")[6]+","+line.split(",")[7]))}
builder(
Child :villas.collect(),
"Clone": [],
"Birth": 2,
"TT": 11,
"Clock": ${__time(/1000,)}
)
log.info(builder.toPrettyString())
vars.put("payload", builder.toPrettyString())
And I could see below response only:
Note: I dont know how to declare "Key" value (line.split(",")[0]) in the above solution.
{
"Child": [
{
"post": "\"\"\"Kid-R\"\":1\"",
"var": "\"[2,2]\"",
"Tar": "\"[1,1]\"",
"Fur": "\"[3,3]\""
},
{
"post": "\"\"\"Kid-R\"\":2\"",
"var": "\"[2,2]\"",
"Tar": "\"[1,1]\"",
"Fur": "\"[3,3]\""
}
],
"Clone": [],
"Birth": 2,
"TT": 11,
"CLock": 1585219797
}
Any help would be greatly appreciated
You're copying and pasting the solution from this answer without understanding what you're doing.
If you change class name from VILLA to own you need to use new own instead of new VILLA
Also this line won't compile: Clock: <take system current time> you need to use System.currentTimeMillis() or appropriate function of the Date class in order to generate the timestamp.
If you want a comprehensive answer, you need to provide:
Well-formatted CSV file
Valid JSON payload
In the meantime I would recommend getting familiarized with the following material:
Apache Groovy: Parsing and producing JSON
Apache Groovy - Why and How You Should Use It
Reading a File in Groovy
Actually I am gonna follow DmirtiT suggestions, as mentioned in some of post to use random variable for bulk API request. Same answer it helped me here as well to generate multiple JSON structure with unique data. Thanks..
This is a json of an api. my query only asks for one language (here "en") so there is only one value in the json. And this is the only thing i want to read in the json. So i think i doesnt make sense to convert it to an object. I thought of something like:
JsonNode root = mapper.readTree(genreJson); ...
But how do i get the value without knowing the name of the attribute (in the example "12345"). This is an Id i dont have.
What do you think?
{
"entities":
{
"12345":
{
"id": "12345",
"type": "item",
"descriptions":
{
"en":
{
"language": "en",
"value": "the_value_i_want"
}
}
}
},
"success": 1
}
i thought something like
JsonNode root = mapper.readTree(genreJson); ...
try this.. may work
JsonNode value = root.path("entities").path("12345").path("descriptions").path("en").path("value");
I am not sure if its an efficient approach though
My problem is that i am serializing the content of map to JSON.
In the output (JSON), i have object that follow key/name syntax rule.
The key is created from map key, and the name from the value.
Model Example:
class Storage {
Map<String,String> values = new HashMap<>();
{
map.put("key1","key1");
map.put("key2","key2");
map.put("key3","key3");
}
}
JSON Example object:
{
key1=value1,
key2=value2,
key3=value3
}
JSON Schema:
{
"name": "storage",
"description": "Store of key values",
"properties": {
// How can we describe the properties if we do not know the name ?
}
}
The issue is that i do not know what the values will be but i know that they will be some.
Can you help me to provide me the full definition of schema?
Disclaimer:
I know that this can be also serialized as
{
values: [
{key="key1", value="value1"},
{key="key2", value="value2"},
{key="key3", value="value3"}
]
}
but is do not want to have array in the JSON.
Assuming your validator supports it you can use patternProperties.
For the schema...
{
"title": "Map<String,String>",
"type": "object",
"patternProperties": {
".{1,}": { "type": "string" }
}
}
...and the document...
{
"foo":"bar",
"baz":1
}
...the value of property foo is valid because it is a string but baz fails validation because it is a number.
I used the Solution suggested by #augurar
"additionalProperties": { "type": "string" }
for AWS API Gateway Model .... and the SDK was able to generate the Map variable as required in Java / Android SDK
#Arne Burmeister - in my case - Solution 1 didnt worked as needed - although it didnt gave any error in the Model (Schema Created)
Like, I have a json file
"ref": [{
"af": [
1
],
"speaker": true,
"name": "Fahim"
},
{
"aff": [
1
],
"name": "Grewe"
}]
During parsing time, If a field is not available in every array(like here speaker). It should throw Null Pointer Exception. So, what are the procedure for parsing those field that not has in every array.
A nice JSON parsing library like this one will have different levels of validation :
https://code.google.com/p/quick-json/
you can set custom validation rules, or use a non-validating version which will just parse without checking standards etc.
Have you tried:
var ref = YourObject.ref;
for(var i=0; i<ref.length; i++){
if(ref[i].speaker!==null){
//do something
}
}