Flink keyBy over option list - apache-flink

My dummy flink job
import org.apache.flink.streaming.api.scala._
import org.json4s.NoTypeHints
import org.json4s.native.Serialization
import org.json4s.native.Serialization.read
case class Label(name: String, typ: String)
case class MyData(id: String, labels: Option[List[Label]] )
object WindowWordCount {
implicit val formats = Serialization.formats(NoTypeHints)
def main(args: Array[String]) {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.getConfig.setParallelism(1)
val packetSource = env
.socketTextStream("localhost", 7777)
.map(json => read[MyData](json))
env.execute("Window Stream WordCount")
}
}
So, each MyData object have unique id and can have multiple labels.
What im going to do is do .keyBy by label.
Incoming data example (serialized to MyData)
{
"id": "1",
"labels": [
{
"name": "unolabelo",
"typ": "two"
},
{
"name": "twunolabelo",
"typ": "two"
}
]
}
If a single MyData element comes with 3 different labels i need to emit 3 MyData elements with a unique label and then i can do .keyBy(_.label) .
What is the best way to do this?

So, if I understand correctly You want to replicate Your message for every label in labels. I think the simplest idea is to simply create another class, say MyDataSimple that will only have single label and then use FlatMapFunction to map MyData to MyDataSimple like:
val myData = ...
myData.labels.map(label => MyDataSimple(label,...))
And then You can do something like:
val packetSource = env
.socketTextStream("localhost", 7777)
.map(json => read[MyData](json))
.flatMap(new MyFlatMapFunction())
.keyBy(_.label)

Solved by applying .flatMap function
val packetSource = env
.socketTextStream("localhost", 7777)
.map(json => read[MyData](json))
.flatMap(
new FlatMapFunction[MyData,MyData] {
override def flatMap(value: MyData, out: Collector[MyData]): Unit = {
value.labels match {
case Some(labels) =>
for (label <- labels) {
out.collect(value.copy(labels = Some(List(label))))
}
case None =>
}
}
}
)
.keyBy(_.labels.get.head.name)

Related

display content-type(Strategy) fields value in the form of array in groovy

I have a snippets of groovy code (inside strategy.groovy file) as shown below in which I want to display the output in the form of desired array.
The content-type Strategy (in crafter) has the following fields:
Title English (title_en_t)
Title French (title_fr_t)
Description English (description_en_t)
Description French (description_fr_t)
Players (players_o)
groovy code (inside strategy.groovy file):
private createStrategyElement(rootStrategy, ctx) {
Element strategy = new DefaultElement("strategy")
strategy.addElement("players_o.first_name_s").text = rootStrategy.players_o.item.component.first_name_s != null ? rootStrategy.players_o.item.component.first_name_s : "" //Line A
strategy.addElement("players_o.last_name_s").text = rootStrategy.players_o.item.component.last_name_s != null ? rootStrategy.players_o.item.component.last_name_s : "" //Line B
return strategy
}
Line A and Line B display the o/p in the following fashion:
current o/p:
players_o.first_name_s: "[John, The]"
players_o.last_name_s: "[Cena, Undertaker]"
PROBLEM STATEMENT:
I am wondering what changes I need to do in the groovy code above at Line A and Line B so that it displays the o/p in this fashion:
DESIRED O/P:
players: [{
"item": [
{
"first_name_s": "John",
"last_name_s": "Cena"
},
{
"first_name_s": "The",
"last_name_s": "Undertaker"
}
]
}]
don't know what is the crafter-cms. and you have not provided the input for your code.
i found DefaultElement and addElement in dom4j library - so i assume it's the one used in crafter-cms
https://dom4j.github.io/javadoc/2.0.1/org/dom4j/tree/DefaultElement.html
you are expecting json in output but dom4j used to work with xml...
however. just a try
private createStrategyElement(rootStrategy, ctx) {
Element strategy = new DefaultElement("strategy")
def players = strategy.addElement('players')
for(i in rootStrategy.players_o.item.component){
def item = players.addElement('item')
item.addElement('first_name_s').text = i.first_name_s
item.addElement('last_name_s').text = i.last_name_s
}
return strategy
}
the following code i used to debug it in standard groovy console:
#Grab(group='org.dom4j', module='dom4j', version='2.1.3')
import org.dom4j.tree.DefaultElement
import org.dom4j.Element
import org.dom4j.io.XMLWriter
import org.dom4j.io.OutputFormat
def rootStrategy=[
players_o:[
item:[
component:[
[
first_name_s:'John',
last_name_s: 'Cena',
],
[
first_name_s:'The',
last_name_s: 'Undertaker'
],
]
]
]
]
private createStrategyElement(rootStrategy, ctx) {
Element strategy = new DefaultElement("strategy")
def players = strategy.addElement('players')
for(i in rootStrategy.players_o.item.component){
def item = players.addElement('item')
item.addElement('first_name_s').text = i.first_name_s
item.addElement('last_name_s').text = i.last_name_s
}
return strategy
}
println new StringWriter().with{w->
new XMLWriter(w, OutputFormat.createPrettyPrint()).write( createStrategyElement(rootStrategy,null) )
w.toString()
}

Kotlin Gson parsing Json Object and Array

I am pretty new to Kotlin and Json and on my work I use GSON to parse the Json.
I need to parse the following Json file into a Class by using GSON.
{
"apiKey": "blablabla",
"baseUrl": "blablabla",
"requestData": [
{
"lng": "6.971",
"lat": "50.942",
"rad": "1.5",
"type": [
"diesel",
"super"
]
},
{
"lng": "6.442",
"lat": "51.180",
"rad": "1.5",
"type": [
"diesel",
"super"
]
},{
"lng": "7.136",
"lat": "50.991",
"rad": "1.5",
"type": [
"diesel",
"super"
]
}
]
}
Now I tried to make a data class like this:
data class ApiParameterData(
var apiKey: String? = null,
var baseUrl: String? = null,
var requestData: String? = null) {
}
I also made another class to store the Json informations in it like this:
class Tankstelle: JsonDeserializer<ApiParameterData> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?
): ApiParameterData {
json as JsonObject
val apiKey = json.get("apiKey").asString
val baseUrl = json.get("baseUrl").asString
val requestDataJson = json.get("requestData")
val requestData = if (requestDataJson.isJsonObject) requestDataJson.asJsonObject.toString() else requestDataJson.toString()
return ApiParameterData(apiKey, baseUrl, requestData)
}
}
I tried to call it like that:
val gsonConfig = GsonBuilder().registerTypeAdapter(ApiParameterData::class.java, Tankstelle()).create()
val tanke = gsonConfig.fromJson(readJson, ApiParameterData::class.java)
println(tanke.requestData?.get(0))
But of course the output I get is "[" . I think because I get back a String or something and this is the first symbol of it?
I need to loop trough the requestData list and store it as a instance of a class and need to access each different value.
The thing is that I want to give the Json file different places and ranges it should look for gasstations. By reading the Json it should take all the pieces and create a link for each place I write in the requestData list. So in this case I would need 3 different links at the end. But this is another part I can do myself. I just don't know how to parse it so I can access and store every value in this Json.
Thank you already and have a great weekend!
If you need more informations just let me know
First you need to define two types that map to your JSON structure
class ApiParameterData(
val apiKey: String,
val baseUrl: String,
val requestData: List<RequestObject>
)
class RequestObject(
val lng: String,
val lat: String,
val rad: String,
val type: List<String>
)
Now simply parse it as
val apiData = Gson().fromJson(readJson, ApiParameterData::class.java) // No need to add TypeAdapter
// To get requestData
val requestData = apiData.requestData
requestData.forEach {
print("${it.lng}, ${it.lat}, ${it.rad}, ${it.type})
}

Data Class Either Object or Array

I have a Kotlin data class that has an arg that can either be an Object or Array. Is there a way to de-serialize a string into this class and not care if not an Array but somehow get it into an array of one?
data class Game(var name:List<NameItem>)
data class NameItem(var title: String, var id: Int)
data can come back as both ways a single object or an array of objects( I have no control over the data as it is 3rd party data.
jsonString = "{"game":{"name":{"title":"GameName","id":22}}}"
jsonString = "{"game":{"name":[{"title":"GameName","id":22},{"title":"GameName2","id":23}]}}"
game: Game? = Gson().fromJson(jsonString Game::class.java)
You have to write a custom JsonDeserializer. Both or your class should have the same parent class. Then, write a custom JsonDeserializer for this specific type.
For example:
sealed class GameParent() {
data class Game(val name: String): GameParent()
data class GameList(val games: List<Game>): GameParent()
}
class GameDeserializer : JsonDeserializer<GameParent> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): GameParent {
with(json) {
if(isJsonObject) {
// parse as Game
}
if(isJsonArray) {
// parse as GameList
}
}
}
}
Then, in your GsonBuilder you have to register this custom JsonDeserializer:
gsonBuilder.registerTypeAdapter(GameParent::class.java, GameDeserializer());
Now, whenever your Gson expect GameParent will use registered deserializer.
my suggestions for solving your task
my solution if name is object, replace it with arrays
data class Game(var name:List<NameItem> )
data class NameItem(var title: String, var id: Int)
fun main(args: Array<String>) {
var json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1},{\"title\":\"game 2\",\"id\":2}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":{\"title\":\"game 1\",\"id\":1}}}" // not array
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1)])
}
version 1 -- created and registry adapter link #Cililing
fun useJsonParser(json: String): Game? {
val gson = GsonBuilder().registerTypeAdapter(Game::class.java, GameDeserializer()).create()
return gson.fromJson(json, Game::class.java)
}
class GameDeserializer : JsonDeserializer<Game?> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Game? {
val gameJson = json!!.asJsonObject.get("game")
if (gameJson.isJsonObject) {
val jsonName = gameJson.asJsonObject["name"]
val list = if (jsonName.isJsonObject) {
arrayOf(Gson().fromJson(jsonName, NameItem::class.java))
} else {
val fromJson = Gson().fromJson(jsonName, Array<NameItem>::class.java)
fromJson
}.toList()
return Game(list)
}
return null
}
}
version 2 -- manipulating the response
fun useJsonParser(json:String):Game?{
val jsonObject = JsonParser().parse(json).asJsonObject.get("game")
if(jsonObject.asJsonObject["name"].isJsonObject){
val jsonName = jsonObject.asJsonObject["name"].asJsonObject
val array = JsonArray()
array.add(jsonName)
jsonObject.asJsonObject.add("name", array) // rewrite origin JSON
}
return Gson().fromJson(jsonObject, Game::class.java)
}
vesrion 3 -- add adapter TypeToken>()
fun useJsonParser(json: String): Game? {
val type = object : TypeToken<MutableList<NameItem>>() {}.type
val gson = GsonBuilder().registerTypeAdapter(type, NameItemDeserializer()).create()
return gson.fromJson(JsonParser().parse(json).asJsonObject.get("game"), Game::class.java)
}
class NameItemDeserializer : JsonDeserializer<List<NameItem>?> {
override fun deserialize(json: JsonElement, type: Type, context: JsonDeserializationContext?): List<NameItem>? {
with(json){
return if(isJsonObject){
arrayListOf(Gson().fromJson(this,NameItem::class.java))
}else{
Gson().fromJson(this,Array<NameItem>::class.java).toList()
}
}
}
}

Copy Array from http request to other array in Angular

I pretty new to angular and I have a question.
I need 2 arrays for ng2-charts, one with labels and one with data.
I make http request to AWS and I got this json
{
"System1": [
{
"name": "MF3",
"descr": "Multifilo MF3",
"speed": [1,2,3,4],
"time": ["10.01", "10.02", "10.03", "10.04"]
}
]
}
I assing all the result to result: Array<SystemModel>;
For use speed and time on ng2-charts I have to copy the two array speed and time on new array: public lineChartSpeed: Array<number> = []; and public lineChartTime: Array<any> = [];
How can I copy this 2 array on my new array? I know how to access to data only on html template, but not on typscript file...
My component is:
public lineChartSpeed: Array<number> = [];
lineChartTime: Array<any> = [];
result: Array<ImpiantoModel>;
getdata() {
this.http.get<SystemModel[]>(this.myUrl)
.subscribe(
data => { this.result = data;
// perform the copy of speed and time on lineChartTime and lineChartSpeed
});
}
How can I copy the array?
If you need more details, please ask in the comments!
thank you !
var system1 = {
"System1": [
{
"name": "MF3",
"descr": "Multifilo MF3",
"speed": [1,2,3,4],
"time": ["10.01", "10.02", "10.03", "10.04"]
}
]
}
var speed = system1.System1[0].speed
var time = system1.System1[0].time
console.log('Array of Speed', speed)
console.log('Array of Time', time)
//Merge or concatenate two Arrays
var newArray = [...speed, ...time]
console.log('Merged or concatenated Arrays', newArray)
Use slice operator to create a new copy of the array
this.result = data.slice();
this.lineChartSpeed = [].concat(this.result[0].speed);
this.lineChartTime = [].concat(this.result[0].time);

How do I use groovy jsonbuilder with .each to create an array?

I would like to create an array with JSON-Builder.
Expected format:
{
"Header": {
"SomeKey" : "SomeValue"
}
"Data": [
{
"SomeKey" : "SomeValue"
},
{
"SomeKey" : "SomeValue"
}
]
}
My Code:
def builder = new groovy.json.JsonBuilder()
def root = builder {
Header {
"Typ" "update"
"Code" "UTF-8"
"TransaktionsNr" item.transactionNumber
"DatumZeit" new Date().format("dd.MM.yyyy HH:mm")
}
customers.each ({ customer->
"Data" {
"Email" customer.code
"Newsletter" customer.newsletterSubscribed
}
})
However whatever I do I only get one element in the Data section. I tried using [] instead of {}, but I still only get one element, what am I doing wrong?
That's duplicate key for JSON structure. There should not be duplicate key in the same hierarchy or they will override each other:
class Customer { String code; boolean newsletterSubscribed }
customers = [
new Customer(code:"11111", newsletterSubscribed:true),
new Customer(code:"22222", newsletterSubscribed:false)
]
def builder = new groovy.json.JsonBuilder()
def root = builder {
Header {
"Typ" "update"
"Code" "UTF-8"
"TransaktionsNr" 987
"DatumZeit" new Date().format("dd.MM.yyyy HH:mm")
}
customers customers.collect { customer ->
["Email":customer.code,
"Newsletter":customer.newsletterSubscribed]
}
}
assert builder.toString() == {"Header":{"Typ":"update","Code":"UTF-8","TransaktionsNr":987,"DatumZeit":"21.12.2012 13:38"},"Data":{"Email":"22222","Newsletter":false},"customers":[{"Email":"11111","Newsletter":true},{"Email":"22222","Newsletter":false}]}

Resources