I was working on an azure stream analytics project which processed device telemetry data from event hub.The input has multiple JSON Arrays and I needed to convert my output to a wide format csv file.In this blog I will walk you through how to do this.
Azure Stream Analytics offers a SQL query language for performing transformations and computations over streams of events.
This is a subset of T-SQL syntax.For my current requirement this fitted well.One can directly write the query in the azure portal and test it there.I also found Visual studio code extensions for Azure stream analytics allows us to craft the query locally with sample mock input data .
The problem-I need to flatten the Input json which has temperature readings and pollution readings from a sensor.These are arrays which may be of differing length
The sample
input JSON
{
"sensor_readings": {
"readings":{
"temperature_readings": [
{
"date": "02-02-2020",
"hour": "12",
"second": "00",
"temperature": "1.12"
},
{
"date": "02-02-2020",
"hour": "13",
"second": "00",
"temperature": "2.12"
}
]
,
"air_pollution_readings":
[
{
"date": "02-02-2020",
"hour": "12",
"second": "00",
"element":"o3",
"particulate": "2.2"
},
{
"date": "02-02-2020",
"hour": "13",
"second": "00",
"element":"o3",
"particulate": "2.1"
},
{
"date": "02-02-2020",
"hour": "14",
"second": "00",
"element":"o3",
"particulate": "1.1"
}
]}
}
,
"siteid": "a1234566",
"deviceid": "2343434"
}
For the first step we need to iterate through all the array elements in each of the arrays
This can be done with the
GetArrayElements array function
with
temp_q as(
SELECT
temp_sensor.ArrayValue as av,
temp_sensor.ArrayIndex as ax,
e.siteid,
e.deviceid,
'temp' as type
FROM
Input1 e
outer apply
GetArrayElements(e.sensor_readings.readings.temperature_readings) as temp_sensor
)
This will flatten the temperature_readings JSON Array
Same goes with the air pollution sensor data
air_q as(
SELECT
temp_sensor.ArrayValue as av,
temp_sensor.ArrayIndex as ax,
e.siteid,
e.deviceid,
'air' as type
FROM
Input1 e
outer apply
GetArrayElements(e.sensor_readings.readings.air_pollution_readings) as temp_sensor
),
tot_q as(
select
*
from
temp_q
union
SELECT
*
from
air_q
)
All array elements in long format for both temperature and air_pollution sensor
Output will look like
{"av":{"date":"02-02-2020","hour":"12","second":"00","temperature":"1.12"},"ax":0,"siteid":"a1234566","deviceid":"2343434","type":"temp"}
{"av":{"date":"02-02-2020","hour":"13","second":"00","temperature":"2.12"},"ax":1,"siteid":"a1234566","deviceid":"2343434","type":"temp"}
{"av":{"date":"02-02-2020","hour":"12","second":"00","element":"o3","particulate":"2.2"},"ax":0,"siteid":"a1234566","deviceid":"2343434","type":"air"}
{"av":{"date":"02-02-2020","hour":"13","second":"00","element":"o3","particulate":"2.1"},"ax":1,"siteid":"a1234566","deviceid":"2343434","type":"air"}
{"av":{"date":"02-02-2020","hour":"14","second":"00","element":"o3","particulate":"1.1"},"ax":2,"siteid":"a1234566","deviceid":"2343434","type":"air"}
Now we want to convert long format to wide .This can be done with the WITH syntax in addition to the JOIN operation.
JOINs only allow LEFT OUTER and INNER joins. We will first need to know which of the arrays are larger and which are smaller .We will then join first using the larger query
processed_q as(
select
case when p.temp_count > = p.air_count then 'temp' else 'air' end larger,
case when p.temp_count < p.air_count then 'temp' else 'air' end smaller,
*
from
(
SELECT
t.deviceid,
tot_q.ax,
tot_q.type,
tot_q.av,
GetArrayLength(t.sensor_readings.readings.temperature_readings) as temp_count,
GetArrayLength(t.sensor_readings.readings.air_pollution_readings) as air_count
from
Input1 t
left outer join tot_q
on tot_q.deviceid = t.deviceid AND DATEDIFF(minute, t, tot_q) BETWEEN 0 AND 0
) p
),
first_join as(
select
*
from
processed_q
where
type = larger
),
To the output obtained we join the smaller and filter out rows where the array pos are not same since its a left outer it will pick up all the rows from the larger array.This will give us the required output
reqd_join as(
select
n.smaller,
n.larger,
n2.type,
n.deviceid,
n.ax,
n.av,
n2.ax as smaller_ax,
n2.av as smaller_av
from
first_join n
left outer join tot_q n2
on n.deviceid = n2.deviceid and n2.type = n.smaller AND DATEDIFF(minute, n2, n) BETWEEN 0 AND 0 and n.ax = n2.ax
)
Output Test
Same number of rows in both arrays
{"smaller":"air","larger":"temp","type":"air","deviceid":"2343434","ax":0,"av":{"date":"02-02-2020","hour":"12","second":"00","temperature":"1.12"},"smaller_ax":0,"smaller_av":{"date":"02-02-2020","hour":"12","second":"00","element":"o3","particulate":"2.2"}}
{"smaller":"air","larger":"temp","type":"air","deviceid":"2343434","ax":1,"av":{"date":"02-02-2020","hour":"13","second":"00","temperature":"2.12"},"smaller_ax":1,"smaller_av":{"date":"02-02-2020","hour":"13","second":"00","element":"o3","particulate":"2.1"}}
Temperature array has more rows than air pollution array .Note that the air pollution smaller_ax and smaller_av is null
{"smaller":"air","larger":"temp","type":"air","deviceid":"2343434","ax":0,"av":{"date":"02-02-2020","hour":"12","second":"00","temperature":"1.12"},"smaller_ax":0,"smaller_av":{"date":"02-02-2020","hour":"12","second":"00","element":"o3","particulate":"2.2"}}
{"smaller":"air","larger":"temp","type":"air","deviceid":"2343434","ax":1,"av":{"date":"02-02-2020","hour":"13","second":"00","temperature":"2.12"},"smaller_ax":1,"smaller_av":{"date":"02-02-2020","hour":"13","second":"00","element":"o3","particulate":"2.1"}}
{"smaller":"air","larger":"temp","type":null,"deviceid":"2343434","ax":2,"av":{"date":"02-02-2020","hour":"14","second":"00","temperature":"3.12"},"smaller_ax":null,"smaller_av":null}
Air pollution array has more rows.
{"smaller":"temp","larger":"air","type":"temp","deviceid":"2343434","ax":0,"av":{"date":"02-02-2020","hour":"12","second":"00","element":"o3","particulate":"2.2"},"smaller_ax":0,"smaller_av":{"date":"02-02-2020","hour":"12","second":"00","temperature":"1.12"}}
{"smaller":"temp","larger":"air","type":"temp","deviceid":"2343434","ax":1,"av":{"date":"02-02-2020","hour":"13","second":"00","element":"o3","particulate":"2.1"},"smaller_ax":1,"smaller_av":{"date":"02-02-2020","hour":"13","second":"00","temperature":"2.12"}}
{"smaller":"temp","larger":"air","type":null,"deviceid":"2343434","ax":2,"av":{"date":"02-02-2020","hour":"14","second":"00","element":"o3","particulate":"3.1"},"smaller_ax":null,"smaller_av":null}
Github
No comments:
Post a Comment