ElasticSearch Groovy script called from Java, how to iterate on all parameters? - java

In my java code I call a groovy script that update an index elasticsearch. I pass a Map in parameter of this script.
The call in the java code is done like this :
// params is a Map<String, String> fullfill
params.put("date","2017-0-23");
params.put("sun","good");
request.script(new Script("myscript", ScriptType.FILE, "groovy", params));
request.upsert("{}");
request.scriptedUpsert(true);
try {
client.update(request).get();
}
Then in the groovy script i do something like this :
newmap = ['date': date,
'sun': sun,
]
So i create a new map and i fill it with some values of the map 'params' from java. If i create a new map it is because i want to do a little traitment on the map i passed in parameter.
But my problem is that if my java map contains a key "date" with a value "2017-08-23" i only know how to access to the value "2017-08-23" and i do this just by writting date in the script (so the key of the java map).
Is there a way to access to some element of the map that i don't know the name ? In fact I want to iterate on all the content of my java map and get the key and the value.
I read all of that page but i don't find any solution https://www.elastic.co/guide/en/elasticsearch/reference/2.3/modules-scripting.html
I have never use Groovy, excepted in that case, but it's seems that the content of my java map is transformed in something called "named parameter" in groovy.
Thank you by advance.

In groovy, you can iterate over a map (or a lot of things, really) using .each. For example:
def test = [one: 1, two: 2, three: 3]
test.each { k, v -> println k }
Prints out
one
two
three
The values are accessible in the closure (.each) as "v". You can call your keys and values what you want in the closure, but convention says k and v are convenient.
​

Related

**EMERGE** (Java) Hashmap single key multi values, locate key in multi values Node

The code below just to demonstrate an example of my code.
LinkedHashMap<String, String> studentID = new LinkedHashMap<String, String>();
//studentID.put("P01", "P06" + "P07");
studentID.put("P02", "P08" + "P09");
studentID.put("P03", "P10");
studentID.put("P04", "P11");
studentID.put("P05", "P12");
System.out.println(studentID.containsValue(P06));
So what I am struggling here is when there are multiple values in hashmap, Java will not be able to put up individual value as human do, for instance, System.out.println(studentID.containsValue(P06));, I am trying to locate P06 only but the program will display false as in it cannot pick up multiple values, in fact, it merged multiple values into one. Does anyone knows any solutions the I can search a single value when that value is based in a multi-values hashmap, and also but break when comes to using a key to search and allocate all values in the line, thank you.
You can use the stream API.
boolean found = studentID.values().stream().
anyMatch(value -> value.contains("P06"));
System.out.println(found);

Using JsonPath to extract inhomogeneous list as typed objects

I need to parse json with a list of inhomogeneous "items" i.e. each may have different keys/structure but they share one common key (here called "a") that gives the type of the item.
{
"items":[
{"a":1, "d":2},
{"a":2, "b":{"c":2}}
]
}
One way I thought to do this might be to pick out the json string for each "item" from the list at path "$.items" using something like the following,
List<String> jsonStrings = JsonPath.parse(json).read("$.items");
such that the first string would be '{"a":1, "d":2}' and the second would be '{"a":2, "b":{"c":2}}'. This is so that I can continue to ask questions of the inner bits using JsonPath itself. Is this possible? (The code above fails as JsonPath returns a list of maps instead.)
An alternative solution might be to use a JsonPath "query path" (my term) to return only "items" with e.g. a = 2 as a list of maps - or a list of typed objects that match the nested structure of each item type, (perhaps sharing a super interface containing the type key as a field). Is this possible?
$.items doesn't work because it's not a list of strings. It's an array of JSON objects.
I'm not sure exactly what you're looking for, but there are several ways to handle it:
$.items.[*].a
Will return all values of a. This might be okay if everything has an a:
[1, 2]
If you want to get something with a specific value for a, you can use the following syntax:
$.items[?(#.a == 2)]
This returns:
[
{
"a": 2,
"b": {
"c": 2
}
}
]
See the JSONPath Github page for other examples.

How to iterate and remove keys from Map<String , Map<String, Set<String>>>

I am having map this way,
Map<String, Map<String, Set<String>>> sampleMap = new Map<String, Map<String, Set<String>>>();
and the data in this map would be this way,
sampleMap={2014={A=[1, 2], B=[3], 2015={A=[1,2], B=[1,2], 2016={A=[1,2], B=[3,4]}};
I want to remove the key's from the map based on this input: List<String> filter; with values this way,
filterArray : [2014, 2015]
i.e, first iterate through arraylist values one by one, verify if the arraylist value matches with any of the key in Hashmap.
if key is matched ignore it.
if key is not matched, I just want to remove that key from the map.
i.e, I always want to keep only matched keys in map, comparing with the input value passed.
In this case, as I have arraylist values this way,[2014,2015],
2014,2015 keys only to be in my map. So,
Data to be before removal:
sampleMap={2014={A=[1, 2], B=[3], 2015={A=[1,2], B=[1,2], 2016={A=[1,2], B=[3,4]}};
Data to be after removel:
sampleMap={2014={A=[1, 2], B=[3], 2015={A=[1,2], B=[1,2]}};
I tried this way, However I just want to know is this is the correct approch, or is it is prone to any of the exceptions?
Iterator<Map.Entry<String , Map<String, Set<String>>>> iter = sampleMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String , Map<String, Set<String>>> entry = iter.next();
logger.info("Keys : " + entry.getKey());
if (filterArray.equalsIgnoreCase(entry.getKey())) {
iter.remove();
}
}
Use retainAll() on the keySet:
map.keySet().retainAll(list);
Seems reasonable. I might have a couple pieces of advice.
First of all, whenever I see nested collections I always wonder if there should be a class or two in there. If this is a one-time task then don't worry about it, but if you want to reuse this code you might want to think about creating a class for your inner map/set... but if it's really this simple then it's no big deal.
Secondly if you are using Java 8, using a list comprehension for filtering would perform better (Because it would automatically thread your compares) and would be cleaner. I can give you the groovy solution for what you are trying to do, but I'm not familiar enough with java 8 list comprehensions to do it correctly.
def filteredStructure=structure.findAll{entry->entry.key.equalsIgnoreCase("2014") || entry.key.equalsIgnoreCase("2015"))
The java version should be really similar.

Assign a name to every element of an array?

Is it possible to assign a name to every element of an array? For example in an array myArr[5], can I give myArr[0] the name "First", myArr[1] "Second" and so on? And if not, what might be a feasible way to achieve a similar result?
Use a Map:
Map<String, Whatever> yourMap = new HashMap<>();
yourMap.put("First", something);
yourMap.put("Second", somethingElse);
Then, to get elements out:
System.out.println(yourMap.get("First")); // prints something.toString()
System.out.println(yourMap.get("Second")); // prints somethingElse.toString()
// etc.
But if you're just going to use "First" and "Second" as keys, you're probably better off just using an array. Maps are useful when it's more convenient to access things using arbitrary objects rather than simple integers as keys.

Generating Java Map or Property trees from flat name value pairs

There are have been numerous times where I have wanted a library that given some simple key value properties creates a tree of maps (and or lists) (a map containing maps.. think Java JSON) and or retrieves and sets values on an existing tree of maps.
An Example (property order is important):
a.b = "b"
a.c.d = 1
a.e.f[0] = "blah"
The above would be parsed into Map<String,?> where a is Map and c is a key in a with the value of a Map contains key of d with the value 1... etc.
A way to visualize this is as a JSON tree:
{
"a" :
{
"b" : "b",
"c" :
{
"d" : 1
},
"e" :
{
"f" :
["blah"]
}
}
}
I have ran into this many times of needing a simple object path like language and general expression languages will not work as the collections are not automatically created.
Consequently I have written my own simple split on . and recursively create maps but I am hoping that perhaps there is a well tested library that allows Java Object manipuluation/creation with out the overhead of a general purpose or turing complete expression language (ie Groovy and EL would be overkill).
I know that Spring has a DataBinder which does something analogous but it only works on POJOs and will not work on a general Map (this is because it needs to know how to convert the data which is not an issue here).
Here is another example of someone trying to do something similar albeit with Jackson: http://pastebin.com/F4feRr8y

Categories