JOLT Introduction
JOLT Introduction
2013
What it is :
JSON to JSON transform library
Declarative
Streaming
Operates on a fully in memory
tree
Motivation 1:
Option 3.5)
Write custom Java, in a way that minimized
the "Java change" when the "transform" changed
INPUT OUTPUT
{ {
"rating": { "Rating":4,
"quality": { "SecondaryRatings": {
"value": 3, "quality": {
}, "Value": 3
"primary": { }
"value": 4 }
} }
}
}
3 -> "Rating.SecondaryRatings.quality.Value"
5 -> "Rating.SecondaryRatings.quality.Range"
Transform Separable Concerns 2:
Maintain Output “format”.
Input : Half DevApi New Output
{ {
"Rating": 4, "Rating": 4,
"SecondaryRatings": { "RatingRange": 5,
"quality": { "SecondaryRatings": {
"Value": 3, "quality": {
} } } "Value": 3,
"Range": 5
} } }
Would be nice...
{
"RatingRange": 5,
"SecondaryRatings" : {
"*" : {
"Range" : 5,
Transform Separable Concerns 3:
Machine Format
Defaultr Output Operate on
{ Map<String,Object> and
"Rating": 4, List<Object>
"RatingRange": 5,
"SecondaryRatings": { and let
"quality": {
"Value": 3,
"Range": 5
}
}
}
handle it.
Recap : ● Operate on Maps-of-Maps
● Small JSON based DSL for each transform "concern"
● Chain them together
[
{ Valid
"operation" : "shift", Operations:
"spec": { ... }
}, "shift",
{ "default",
"operation" : "java", "remove",
"classname" : "com.bazaar.." "sort",
"spec": { ... } // optional "java"
},
{
"operation" : "default"
"spec" : { ... }
}
A Note on Testing :
input doc
shift
custom Java
default
Shiftr Basics :
INPUT { OUTPUT {
"rating": { "Rating": 4,
"quality": { "SecondaryRatings": {
"value": 3, "quality": {
}, "Value": 3
"primary": { }
"value": 4 }
} } } }
SPEC (Starts out as a copy of the INPUT {
"rating": {
"quality": {
"value": "SecondaryRatings.quality.Value",
},
"primary": {
"value": "Rating"
} } }
Shiftr Basics 2 : Send input to two places
INPUT { OUTPUT {
"rating": { "Rating": 4,
"quality": { "PrimaryRating" : 4 ,
"value": 3, "SecondaryRatings": {
}, "quality": {
"primary": { "Value": 3
"value": 4 }
} } } }
}
SPEC {
"rating": {
"quality": {
"value": "SecondaryRatings.quality.Value",
},
"primary": {
"value": [ "Rating", "PrimaryRating" ]
Shiftr Basics 3 : Two inputs to the same place
INPUT { OUTPUT {
"rating": { "allRatings": [ 3, 4 ]
"quality": { }
"value": 3, }
}, Order of array
"primary": { not Guaranteed.
"value": 4
} } }
SPEC {
"rating": {
"quality": {
"value": "allRatings",
},
"primary": {
"value": "allRatings"
} } }
Shiftr WildCards 101 : * and &
INPUT { OUTPUT {
"rating": { "SecondaryRatings": {
"quality": { "quality": {
"value": 3, "Value": 3
}, },
"colour": { "colour" : {
"value": 4 "Value" : 4
} } } } } }
"SecondaryRatings.quality.Value"
"SecondaryRatings.colour.Value"
SPEC {
"rating": {
"*": {
"value": "SecondaryRatings.&1 .Value"
}
} }
Shiftr WildCards 101 : & Explained
INPUT {
"rating": {
"quality": {
"value": 3,
},
"colour": {
"value": 4
} } }
What goes in the green box?
&0 = "value"
& = "value" (sugar)
&1 = "quality" or "colour"
SPEC { &2 = "rating"
"rating": { &3 = Fail
"*": {
"value": "SecondaryRatings. .Value"
}
} }
Shiftr Hangover : Precedence
INPUT OUTPUT
{ {
"rating": { "Rating": 4,
"quality": { "SecondaryRatings": {
"value": 3, "quality": {
}, "Value": 3
"primary": { }
"value": 4 }
} } } }
SPEC {
"rating": {
"*": {
"value": "SecondaryRatings.&1.Value"
}, Has Precedence
"primary" : {
"value" : "Rating"
} }
Shiftr Hangover : Moving SubTrees
INPUT { OUTPUT {
"rating": { "Ratings": {
"quality": { "quality": {
"value": 3, "value": 3,
}, },
"primary": { "primary": {
"value": 4 "value": 4
} } } } } }
SPEC
{
"rating": "Ratings"
}
SPEC
{
"rating-*": {
"@" : "SecondaryRatings.&(0,1).Value",
"$(0,1)" : "SecondaryRatingsOrder.[]"
} }
Shiftr 301 : Explicit Arrays
INPUT { OUTPUT {
"photos": [ "Photos": [
"thumb.jpg", "normal.jpg",
"normal.jpg" "thumb.jpg"
] ]
} }
SPEC {
"photos": {
"0" : "Photos[1]", // sugar
"1" : "Photos.[0]" // canonical
}
}
SPEC {
"photos": {
"0" : "Photos[1]", // sugar
"1" : "Photos.[0]" // canonical
}
}
SPEC {
"photos": {
"*" : {
"caption" : "Photos.[&1].Cap",
"url" : "Photos.[&1].URL",
} } }
Shiftr Final Exam : What is this doing?
Polloi to DevApi Spec for Reviews
{
"~id": "Id",
"~lastUpdateAt": "LastModificationTime",
"about": {
"0": {
"externalId": "ProductId"
}
},
"cdv-*": {
"@": "ContextDataValues.&(0,1).Value",
"$(0,1)": "ContextDataValues.&.Id"
},
"photos": {
"*": {
"mediumImageLegacyId": "Photos[&1].Sizes.medium.Id",
"thumbnailImageLegacyId":"Photos[&1].Sizes.thumbnail.Id",
"largeImageLegacyId": "Photos[&1].Sizes.large.Id",
"caption": "Photos[&1].Caption",
"largeImageExternalUrl": "Photos[&1].Sizes.large.Url"
}
},
Jolt Extras : Tools for your Custom Transform
ElasticSearch to DevApi Spec for Reviews
AssertEquals( 3, qualityRating );
74 lines shift
8 lines custom Java
8 lines default
Performance Takeaway : Pacman Looks Right
Totally Unscientific Concierge Performance Stats
Local Concierge / Local ElasticSearch
Transform
Small Dataset
"Includes" queries, but no facets
Requests
● 52
● 162 ms avg