I have several Apache Flink jobs that are monitored in Datadog.
Problem I'm trying to solve is that I would like to have a single dashboard, and toggle the Flink job names (and environment) so I don't have to build multiple dashboard with the exact same context, but just a different job identifier/name. For instance, this is the JSON for a sample Memory Usage widget that I have:
{
"viz": "timeseries",
"requests": [
{
"style": {
"palette": "dog_classic",
"type": "solid",
"width": "normal"
},
"type": "line",
"formulas": [
{
"alias": "Heap Used",
"formula": "query1"
},
{
"alias": "Heap Max",
"formula": "query2"
},
{
"alias": "Non-Heap Used",
"formula": "query3"
},
{
"alias": "Non-Heap Max",
"formula": "query4"
},
{
"alias": "heap % of max",
"formula": "query1 / query2 * 100"
},
{
"alias": "non-heap % of max",
"formula": "query3 / query4 * 100"
}
],
"queries": [
{
"query": "avg:the_flink_job_name.jobmanager.Status.JVM.Memory.Heap.Used.value{env:$environment.value}",
"data_source": "metrics",
"name": "query1"
},
{
"query": "avg:the_flink_job_name.jobmanager.Status.JVM.Memory.Heap.Max.value{env:$environment.value}",
"data_source": "metrics",
"name": "query2"
},
{
"query": "avg:the_flink_job_name.jobmanager.Status.JVM.Memory.NonHeap.Used.value{env:$environment.value}",
"data_source": "metrics",
"name": "query3"
},
{
"query": "avg:the_flink_job_name.jobmanager.Status.JVM.Memory.NonHeap.Max.value{env:$environment.value}",
"data_source": "metrics",
"name": "query4"
}
],
"response_format": "timeseries"
}
]
}
What I'm trying to achieve is to be able to provide the_flink_job_name as a variable, in the same way env is provided.
Is there a way to accomplish this?
We solved this by setting a global tag per job in the Datadog reporter with the job name: https://nightlies.apache.org/flink/flink-docs-stable/docs/deployment/metric_reporters/#datadog
metrics.reporter.dghttp.tags: flink_job:<job_name>
A bit manual, but should allow you to achieve what you are looking for. We had to do it like this since it seemed there was no other way to create reusable dashboards using template variables.
Related
I'm trying to create a slide show (2-3 images) using the Alexa authoring tool.I have managed to do this using the APL Pager which displays a series of components one at a time. The thing is that in order to switch from image A to image B..C I have to touch the screen and swipe left/right.
i want to make this happen automatically and have alexa swicth the images within a certain time, and it seems that this can be achieved using APL autopage but for some reason this is not working 😩
What I've done
Set up the APL using the APL pager
Added the auto page to the APL document
Component Id
duration
delay
After trying the simulation and directly in an echo show 5 it still only triggers when the display is touched.
Also tried:
Adding the standard command (auto pager) directly in the handler of alexa but same response.
Some doubts
Does it matter if i put the commands in the APLdocument.json[1] file or directly in the handler when i call .addDirective[2]..the only difference i see if i want the content or duration to be dynamic i should put it directly in the backend code(index.js) right?
[1]
{
"type": "APL",
"version": "1.4",
"settings": {},
"theme": "light",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"commands": [
{
"type": "AutoPage",
"componentId": "fisrtpager",
"duration": 1000,
"delay": 500
}
],
[2]
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
token:'arrugas',
document: physiolift,
commands: [{
"type": "AutoPage",
"componentId": "fisrtpager",
"duration": 1000,
"delay": 500
}]
});
}
Expected outPut
Have Alexa (echo show 5) to display a series of images like a carousel (without the need to touch the screen)
My code
APL Document
{
"type":"APL",
"version":"1.4",
"settings":{
},
"theme":"light",
"import":[
],
"resources":[
],
"styles":{
},
"onMount":[
],
"graphics":{
},
"commands":[
{
"type":"AutoPage",
"componentId":"fisrtpager",
"duration":1000,
"delay":500
}
],
"layouts":{
},
"mainTemplate":{
"parameters":[
"payload"
],
"items":[
{
"type":"Pager",
"id":"fisrtpager",
"width":"100%",
"height":"100%",
"items":[
{
"type":"Image",
"width":"100%",
"height":"100%",
"scale":"best-fill",
"source":"https://dyl80ryjxr1ke.cloudfront.net/external_assets/hero_examples/hair_beach_v1785392215/original.jpeg",
"align":"center"
},
{
"type":"Image",
"width":"100%",
"height":"100%",
"source":"https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg",
"scale":"best-fill"
},
{
"type":"Text",
"text":"Just text content shown on page #3",
"textAlign":"center"
}
],
"navigation":"wrap"
}
]
}
}
index.js
// somewhere inside the intent im invoking
if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) {
// Create Render Directive.
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
token:'arrugas',
document: require('./documents/ImageTest.json')
});
}
speakOutput += ' just saying somthing'
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt('just saying something else')
.getResponse();
Just add the command in the "onMount" event handler. Here is the modified code which does exactly what you need:
{
"type": "APL",
"version": "1.4",
"settings": {},
"theme": "light",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"layouts": {},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Pager",
"id": "fisrtpager",
"width": "100%",
"height": "100%",
"items": [
{
"type": "Image",
"width": "100%",
"height": "100%",
"scale": "best-fill",
"source": "https://dyl80ryjxr1ke.cloudfront.net/external_assets/hero_examples/hair_beach_v1785392215/original.jpeg",
"align": "center"
},
{
"type": "Image",
"width": "100%",
"height": "100%",
"source": "https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg",
"scale": "best-fill"
},
{
"type": "Text",
"text": "Just text content shown on page #3",
"textAlign": "center"
}
],
"navigation": "none",
"onMount": [{
"type": "AutoPage",
"componentId": "fisrtpager",
"duration": 1000,
"delay": 500
}]
}
]
}
}
to update dynamically this feature from your backend code you can do the following:
// check if device supports APL
if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) {
// Create Render Directive.
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
token: "dialogManagementPagerDoc",
document: require('./PATH-TO/YOUR-APL-FILE.json')
})
.addDirective({
type: "Alexa.Presentation.APL.ExecuteCommands",
token: "dialogManagementPagerDoc",
commands: [
{
type: "AutoPage",
componentId: "YOUR_PAGER_ID",
delay: 1000,
duration: 5000
}
]
});
}
I'm building a simple Guess Who skill game for Alexa. I have two intents right now: GenderIntent and HairColorIntent.
GenderIntent has a custom slot to handle gender and related synonyms such as mapping "boy" and "man" to "Male". This is working great. It returns a resolution within the slot. Exactly what I need.
HairColorIntent has a predefined Amazon slot, AMAZON.Color. This is not working great as it never returns a resolution regardless of the color supplied.
Here is my model for GenderIntent and HairColorIntent:
{
"name": "GenderIntent",
"samples": [
"are you a {Gender}"
],
"slots": [
{
"name": "Gender",
"type": "GENDER_TYPES",
"samples": []
}
]
},
{
"name": "HairColorIntent",
"samples": [
"is your hair {HairColor}",
"do you have {HairColor} hair"
],
"slots": [
{
"name": "HairColor",
"type": "AMAZON.Color"
}
]
}
GenderIntent returns the following slot WITH resolutions:
{
"Gender": {
"name": "Gender",
"value": "male",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.2ed972f4-1c5a-4cc1-8fd7-3f440f5b8968.GENDER_TYPES",
"status": {
"code": "ER_SUCCESS_MATCH"
},
"values": [
{
"value": {
"name": "Male",
"id": "63889cfb9d3cbe05d1bd2be5cc9953fd"
}
}
]
}
]
},
"confirmationStatus": "NONE",
"source": "USER"
}
}
HairColorIntent returns the following WITHOUT resolutions:
{
"HairColor": {
"name": "HairColor",
"value": "brown",
"confirmationStatus": "NONE",
"source": "USER"
}
}
I'd like HairColorIntent's HairColor slot to return the resolution. What am I doing wrong?
Resolution is only returned if you use synonyms in your slot type.
Not exactly sure how you handle it in your code, for example Node.js would be:
handlerInput.requestEnvelope.request.intent.slots.Gender.resolutions.resolutionPerAuthority[0].values[0].value.name
If you do not use synonyms (for example for the HairColor slot), you can get the value simply by handlerInput.requestEnvelope.request.intent.slots.HairColor.value
Working with predefined slot types this should work well with your code. If you want custom slot types to also return resolution whether you actually use synonyms or not, you can always just simply give the value as a synonym and it should return the full resolution tree.
Hope that answered your question.
I have another question on Azure Search, I have an index called “branchorders-index” (schema attached). I have string field called “lowerCustomerPONbr” with custom analyzer as below:
"analyzers": [
{
"#odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"name": "SWMLuceneAlongWithCustomHyphenAnalyser",
"tokenizer": "keyword_v2",
"tokenFilters": [
"lowercase"
],
"charFilters": []
}
]
Question: What would be the correct query for searching text “engg - test - umesh”? I want a single document on execution of the query. Here is the query I am trying:
$count=true&$select=lowerCustomerPONbr&search=lowerCustomerPONbr:/.*engg\ \-\ test\ \-\ umesh.*/
{
"#odata.context": "https://abcd/indexes('branchorders-index')/$metadata#docs(lowerCustomerPONbr)",
"#odata.count": 8,
"value": [
{
"#search.score": 0.22780417,
"lowerCustomerPONbr": "engg - test - umesh"
},
{
"#search.score": 0.027440047,
"lowerCustomerPONbr": "sam-clc-test-3"
},
{
"#search.score": 0.025132125,
"lowerCustomerPONbr": "sam-clc-test-4"
},
{
"#search.score": 0.019148104,
"lowerCustomerPONbr": "sam-clc-test-1"
},
{
"#search.score": 0.019148104,
"lowerCustomerPONbr": "030 test 17 april"
},
{
"#search.score": 0.018480092,
"lowerCustomerPONbr": "sam-clc-test-2"
},
{
"#search.score": 0.018480092,
"lowerCustomerPONbr": "dilip-qa-test"
},
{
"#search.score": 0.015009361,
"lowerCustomerPONbr": "030 eng-test"
}
]
}
Santosh, if you add &queryType=full, does this fix the issue?
Given my Profile data looks like below, I want to find the profile for combination of userName and productId
and only return the profile with the respective contract for this product.
{
"firstName": "John",
"lastName": "Doe",
"userName": "john.doe#gmail.com",
"language": "NL",
"timeZone": "Europe/Amsterdam",
"contracts": [
{
"contractId": "DEMO1-CONTRACT",
"productId": "ticket-api",
"startDate": ISODate('2016-06-29T09:06:42.391Z'),
"roles": [
{
"name": "Manager",
"permissions": [
{
"activity": "ticket",
"permission": "createTicket"
},
{
"activity": "ticket",
"permission": "updateTicket"
},
{
"activity": "ticket",
"permission": "closeTicket"
}
]
}
]
},
{
"contractId": "DEMO2-CONTRACT",
"productId": "comment-api",
"startDate": ISODate('2016-06-29T10:27:45.899Z'),
"roles": [
{
"name": "Manager",
"permissions": [
{
"activity": "comment",
"permission": "createComment"
},
{
"activity": "comment",
"permission": "updateComment"
},
{
"activity": "comment",
"permission": "deleteComment"
}
]
}
]
}
]
}
I managed to find the solution how to do this from the command line. But I don't seem to find a way how to accomplish this with Morphia (latest version).
db.Profile.aggregate([
{ $match: {"userName": "john.doe#gmail.com"}},
{ $project: {
contracts: {$filter: {
input: '$contracts',
as: 'contract',
cond: {$eq: ['$$contract.productId', "ticket-api"]}
}}
}}
])
This is what I have so far. Any help is most appreciated
Query<Profile> matchQuery = getDatastore().createQuery(Profile.class).field(Profile._userName).equal(userName);
getDatastore()
.createAggregation(Profile.class)
.match(matchQuery)
.project(Projection.expression(??))
Note... meanwhile I found another solution which does not use an aggregation pipeline.
public Optional<Profile> findByUserNameAndContractQuery(String userName, String productId) {
DBObject contractQuery = BasicDBObjectBuilder.start(Contract._productId, productId).get();
Query<Profile> query =
getDatastore()
.createQuery(Profile.class)
.field(Profile._userName).equal(userName)
.filter(Profile._contracts + " elem", contractQuery)
.retrievedFields(true, Profile._contracts + ".$");
return Optional.ofNullable(query.get());
}
I finally found the best way (under assumption I only want to return max. 1 element from array) to filter embedded array.
db.Profile.aggregate([
{ $match: {"userName": "john.doe#gmail.com"}},
{ $unwind: "$contracts"},
{ $match: {"contracts.productId": "comment-api"}}
])
To match according to your first design you could try the projection settings with morphia aggregation pipeline.
Query<Profile> matchQuery = getDatastore().createQuery(Profile.class).field(Profile._userName).equal(userName);
getDatastore()
.createAggregation(Profile.class)
.match(matchQuery)
.project(Projection.expression("$filter", new BasicDBObject()
.append("input", "$contracts")
.append("as", "contract")
.append("cond", new BasicDBObject()
.append("$eq", Arrays.asList('$$contract.productId', "ticket-api")));
Also see the example written by the morphia crew around line 88 at https://github.com/mongodb/morphia/blob/master/morphia/src/test/java/org/mongodb/morphia/aggregation/AggregationTest.java.
I want to implement the following query in Elastic4s. Don't see any way to implement the matched_fields clause in the highlighter. Any help?
{
"query": {
"multi_match": {
"type": "most_fields",
"query": "hello world",
"fields": [ "text", "text.human" ]
}
},
"highlight": {
"order": "score",
"fields": {
"text": {
"matched_fields": [ "text", "text.human" ],
"fragment_size": 100,
"number_of_fragments": 10
}
}
}
}
A question with a very simple answer. You can't do it yet in elastic4s :)
So, I've just added it:
https://github.com/sksamuel/elastic4s/commit/3f8a4e47ae603b7a3263bc3d31c27f2b6706cd8e
This will be in the next 1.5.x release and 1.6.0.