I am wondering if it is possible to achieve follow...
# general
j
I am wondering if it is possible to achieve following similar result by running a groupBy query :
Copy code
[
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "polygon",
        "total": 197944
    },
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "ethereum",
        "total": 1994412
    },
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "celo",
        "total": 1234
    },
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "All Others",
        "total": 123
    },
    .
    .
    .
    {
        "ts": "2024-04-30T11:00:00.000Z",
        "network": "polygon",
        "total": 193953
    },
    {
        "ts": "2024-04-30T11:00:00.000Z",
        "network": "ethereum",
        "total": 19393
    },
    {
        "ts": "2024-04-30T11:00:00.000Z",
        "network": "celo",
        "total": 111
    },
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "All Others",
        "total": 11
    },
]
I am particularly interested in whether we can get the
All Others
by just showing the top3 or top4 and then all others get aggregated into that field
l
Are the top3/4 predefined fields that you wanna separate from the ‘All Others’? If so, you can have a virtual column (CASE..WHEN in SQL) that maps polygon, ethereum, celo to themselves, and rest of the fields to ‘All others’ and group on that column
j
Not really predefined, they can actually be some other network, that example payload does not mean we will always have the Polygon, Ethereum and Celo in top3, they could be something else too
l
by top, do you mean those columns with max “total” count?
j
yes, it could be
Copy code
{
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "A",
        "total": 197944
    },
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "B",
        "total": 1994412
    },
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "C",
        "total": 1234
    },
    {
        "ts": "2024-04-29T12:00:00.000Z",
        "network": "All Others",
        "total": 123
    },
but always with a determined info showing the top3 or the top4 and everything else in
All Others
. The idea is to render a stacked bar chart where each bar will be shown for each timestamp
🙌 1
g
the simplest way i can think of is to do 2 queries: one topN style (get the top 3) and another timeseries style (get the total) and then compute
All Others
on the client side by subtraction i'm sure there's a fancier way, that would actually produce a result from a single query like the one you mentioned, involving window functions. something like the following. however note that it does require window fns (currently experimental) and will also require loading up all of the distinct
countryName
in memory in order to compute the ranks and re-group the "All others". so it will have limitations if there's a lot of distinct
countryName
. (which there aren't, because there aren't that many countries, but there may be a lot of
network
in your example)
Copy code
select
  case when least(rnk, 4) < 4 then countryName else 'All others' end as Country,
  sum("cnt") as "cnt"
from (
  select
    rank() over (order by count(*) desc) rnk,
    countryName,
    count(*) as "cnt"
  from wikipedia
  where countryName is not null
  group by countryName
)
group by 1, least(rnk, 4)
order by least(rnk, 4)
j
hmm I see that would be tricky, obviously I do not think there would be many networks in our case tbh, it pretty much depends also on what the user’s requests are (basically we store user’s requests to our API), from all the networks available through our API, user might only submit requests for 6 or 7 of them. Is there a native json druid query similar to that with window fns?
g
yep, there always is. you can do
explain plan for
on the SQL query to see what the native query would be
j
Thanks Gian. I got the native one but have a question:
Copy code
{
  "queryType": "groupBy",
  "dataSource": {
    "type": "query",
    "query": {
      "queryType": "windowOperator",
      "dataSource": {
        "type": "query",
        "query": {
          "queryType": "groupBy",
          "dataSource": {
            "type": "table",
            "name": "test_dev"
          },
          "intervals": {
            "type": "intervals",
            "intervals": [
              "2024-05-08T12:00:00.000Z/2024-05-09T12:00:00.001Z"
            ]
          },
          "filter": {
            "type": "and",
            "fields": [
              {
                "type": "equals",
                "column": "user_id",
                "matchValueType": "STRING",
                "matchValue": "1234abcd"
              },
              {
                "type": "not",
                "field": {
                  "type": "null",
                  "column": "network"
                }
              }
            ]
          },
          "granularity": {
            "type": "all"
          },
          "dimensions": [
            {
              "type": "default",
              "dimension": "network",
              "outputName": "d0",
              "outputType": "STRING"
            }
          ],
          "aggregations": [
            {
              "type": "count",
              "name": "a0"
            }
          ],
          "limitSpec": {
            "type": "NoopLimitSpec"
          },
          "context": {
            "enableWindowing": true,
            "queryId": "f4b80893-f3ba-4a18-be45-a04ad3e3854a",
            "sqlOuterLimit": 1001,
            "sqlQueryId": "f4b80893-f3ba-4a18-be45-a04ad3e3854a",
            "useNativeQueryExplain": true
          }
        }
      },
      "intervals": {
        "type": "LegacySegmentSpec",
        "intervals": [
          "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z"
        ]
      },
      "context": {
        "enableWindowing": true,
        "queryId": "f4b80893-f3ba-4a18-be45-a04ad3e3854a",
        "sqlOuterLimit": 1001,
        "sqlQueryId": "f4b80893-f3ba-4a18-be45-a04ad3e3854a",
        "useNativeQueryExplain": true
      },
      "outputSignature": [
        {
          "name": "d0",
          "type": "STRING"
        },
        {
          "name": "a0",
          "type": "LONG"
        },
        {
          "name": "w0",
          "type": "LONG"
        }
      ],
      "operatorDefinition": [
        {
          "type": "naiveSort",
          "columns": [
            {
              "column": "a0",
              "direction": "DESC"
            }
          ]
        },
        {
          "type": "naivePartition",
          "partitionColumns": []
        },
        {
          "type": "window",
          "processor": {
            "type": "rank",
            "group": [
              "a0"
            ],
            "outputColumn": "w0",
            "asPercent": false
          }
        }
      ],
      "leafOperators": [],
      "granularity": {
        "type": "all"
      }
    }
  },
  "intervals": {
    "type": "intervals",
    "intervals": [
      "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z"
    ]
  },
  "virtualColumns": [
    {
      "type": "expression",
      "name": "v0",
      "expression": "case_searched((least(\"w0\",4) < 4),\"d0\",'All others')",
      "outputType": "STRING"
    },
    {
      "type": "expression",
      "name": "v1",
      "expression": "least(\"w0\",4)",
      "outputType": "LONG"
    }
  ],
  "granularity": {
    "type": "all"
  },
  "dimensions": [
    {
      "type": "default",
      "dimension": "v0",
      "outputName": "_d0",
      "outputType": "STRING"
    },
    {
      "type": "default",
      "dimension": "v1",
      "outputName": "_d1",
      "outputType": "LONG"
    }
  ],
  "aggregations": [
    {
      "type": "longSum",
      "name": "_a0",
      "fieldName": "a0"
    }
  ],
  "limitSpec": {
    "type": "default",
    "columns": [
      {
        "dimension": "_d1",
        "direction": "ascending",
        "dimensionOrder": {
          "type": "numeric"
        }
      }
    ],
    "limit": 1001
  },
  "context": {
    "enableWindowing": true,
    "queryId": "f4b80893-f3ba-4a18-be45-a04ad3e3854a",
    "sqlOuterLimit": 1001,
    "sqlQueryId": "f4b80893-f3ba-4a18-be45-a04ad3e3854a",
    "useNativeQueryExplain": true
  }
}
I am not sure where this intervals comes from:
-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z
. If I change them for
2024-05-08T12:00:00.000Z/2024-05-09T12:00:00.001Z
then I get null pointer but I found out it is because I need to change the granularity from:
Copy code
"granularity": {
    "type": "all"
  },
to:
Copy code
"granularity": {
    "type": "period",
    "period": "PT1H",
    "timeZone": "Etc/UTC"
  },
however with above changes I get nothing. In order to get results I need to keep granularity type
all
and
-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z
intervals. The SQL query:
Copy code
select
  case when least(rnk, 4) < 4 then network else 'All others' end as Network,
  sum("cnt") as "cnt"
from (
  select
    rank() over (order by count(*) desc) rnk,
    network,
    count(*) as "cnt"
  from "test_dev"
  where "network" is not null and "user_id" = '1234abcd' and __time BETWEEN TIMESTAMP '2024-05-08 12:00:00' AND TIMESTAMP '2024-05-09 12:00:00'
  group by network
)
group by 1, least(rnk, 4)
order by least(rnk, 4)
well probably to get a timeseries result I would need something
Copy code
select
  time_hour,
  case when least(rnk, 4) < 4 then network else 'All others' end as Network,
  sum("cnt") as "cnt"
from (
  select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    rank() over (order by count(*) desc) rnk,
    network,
    count(*) as "cnt"
  from "test_dev"
  where "network" is not null and "user_id" = '1234' and __time BETWEEN TIMESTAMP '2024-05-08 12:00:00' AND TIMESTAMP '2024-05-09 12:00:00'
  group by network, TIME_FLOOR(__time, 'PT1H')
)
group by time_hour, 2, least(rnk, 4)
order by least(rnk, 4)
but not giving the desired result
I have been playing with this one:
Copy code
select
  time_hour,
  case when rnk > 100 then network else 'All others' end as network,
  sum("total") as "total"
from (
  select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (order by count(*) desc) rnk,
    network,
    count(*) as "total"
  from "test_dev"
  where "network" is not null and "user_id" = '1234' and __time BETWEEN TIMESTAMP '2024-05-08 12:00:00' AND TIMESTAMP '2024-05-09 12:00:00'
  group by network, TIME_FLOOR(__time, 'PT1H')
  order by 1 asc
)
group by time_hour, 2
order by 1 asc, 3 asc
however, not sure how best resolve this use case. If we always want the top 3 Networks and everything else in
All Others
label, then for customer
1234
that submits requests to 10 different networks, I guess we get a nice result, but for a customer
abcd
that submits requests to only 2 networks, then it might make not sense to display
All Others
in the result set right?
So, working on the example • user
1234
makes requests up to 8 different networks (we want, e.g. top2 and
All Others
) • user
abcd
only makes requests up to 2 different networks (we do not want
All Others
to be rendered)
g
as to the intervals
-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z
, that's just because there is no time filter. It's how we represent a SQL query with no time filter in a native query [where time filter is required] -- min possible timestamp to max possible timestamp
if you add a time filter to the SQL query then it should show up there
as to the 'all others' in the query you were playing with, i think you might have the rank comparison backwards; you have
case when rnk > 100 then network else 'All others' end as network
, i think you want that to be
< 100
instead of
> 100
j
When you refer to time filter in the SQL, you meant a SQL like this?:
Copy code
select
  time_hour,
  case when least(rnk, 4) < 4 then network else 'All others' end as network,
  sum("total") as "total"
from (
  select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    rank() over (order by count(*) desc) rnk,
    network,
    count(*) as "total"
  from "test_dev"
  where "network" is not null and "user_id" = '1234' and __time BETWEEN TIMESTAMP '2024-05-08 12:00:00' AND TIMESTAMP '2024-05-09 12:00:00'
  group by network, TIME_FLOOR(__time, 'PT1H')
)
group by time_hour, 2, least(rnk, 2)
order by time_hour, network asc
Above I am specifying a time filter and I am getting still in the middle of the json query
Copy code
"intervals": {
        "type": "LegacySegmentSpec",
        "intervals": [
          "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z"
        ]
      },
and near the bottom
Copy code
"intervals": {
    "type": "intervals",
    "intervals": [
      "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z"
    ]
  },
g
i do mean a sql like that yeah
what i expect with a SQL like that is that you would have an
intervals
for
2024-05-08 12:00:00
to
2024-05-09 12:00:00
for one of the subqueries—the one that queries
test_dev
directly— and the
intervals
on the other subqueries will still be
-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z
(each subquery has its own set of
intervals
)
j
all right, however it we were going to generate this json native queries by code, guessing the other intervals in the subqueries might be tricky
basically we expose an API for customers to check their API activity, that API activity gets stored in Druid, so each customer will visit their dashboard and pull data from Druid for specific period (last 15 minutes, last day, etc..) so there is an API transform that into a druid native json query
g
got it, that makes sense
-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z
is kind of like a special interval that means "don't time filter". in our SQL planner code it's a constant
Intervals.ETERNITY
. if you are writing native queries directly you can use it anytime a query or subquery doesn't need to filter what's below it in most cases a more-specific time filter is only needed on the lowest-level query that hits the table directly
j
all right, got it, I can incorporate that into the library, now looking into the code base for druid makes sense
as for the query, I am still not sure if I can accomplish what I wrote here https://apachedruidworkspace.slack.com/archives/C0303FDCZEZ/p1715266623969849?thread_ts=1715078731.127549&amp;cid=C0303FDCZEZ with the screenshots, the queries there are different from the one just above
That rank number can also vary on a customer’s basis, if it is a busy customer then rank gets higher and higher, but for a customer that does not use much the API then rank number is low, perhaps finding avg rank for customers might be a good idea
g
i thought with that comment you were saying that you want to skip
All Others
if the # of networks returned is less than the rank threshold you'd defined? i believe that should happen "automatically" since the
case
statement will never return
All Others
if no network has a rank greater than the number in there
maybe you were saying something else though, it sounds like you might want the rank threshold for
All Others
to be dynamic somehow
j
well it is imposible that it happens dynamically I guess
the number
100
, I added it for testing, but result set differs from customer to customer depending how many requests they have made to our API for specific networks
so examples are screenshots, customer
1234
only requests 2 networks however customer
abcd
8 networks, but on the other hand customer
1234
might only use 2 networks but for 1 network have a rank over 100 and the other network rank of 50, so if I use
100
then result set shows 1 network and
All Others
containing only 1 other network
not sure I am explaining myself
g
are you actually seeing that kind of problem? i think you wouldn't, since the rank is computed based on the result set if a result set for customer
1234
has only 2 networks then one will have rank
1
and one will have rank
2
j
But shouldn’t not we take into account that rank happens over a window? That’s it the PT1H? Data ingested for that data source has 1 minute granularity and aggregated on some fields. So taking into account a user might hit our API at high request per second, then over a minute we have quite a lot of data for different networks. If then the query we do is for PT1H, the rank for a network on a given 1H window is higher than 1 if there are more than one request right? That why we see a number like 46 for some network on a given hour and different rank number for that same network on different hour
g
ah, i missed that you didn't just want a single list of networks, you want a list per hour or some other time period
i feel like there should still be some way to handle that with window functions; perhaps with different partitionings. i don't have a worked example though
the way to do it would also depend on whether you want the 'All others' to be determined for the entire query (so what maps to 'All others' is the same for each time period); or if you want it to be determined per time period
j
I guess the
All Others
should be determined per time period right? but I though we were doing so with following query
Copy code
select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (order by count(*) desc) as rnk,
    network,
    count(*) as "total"
  from "monopipe_dev"
  where "network" is not null and "user_id" = 'c2d6c42a8b0b4da4816cdad307a54850' and __time BETWEEN TIMESTAMP '2024-05-08 12:00:00' AND TIMESTAMP '2024-05-09 12:00:00'
  group by network, TIME_FLOOR(__time, 'PT1H')
  order by 1 asc
or do we somehow have to include the time period within
RANK() over …
?
I think I got it, following query:
Copy code
select
  time_hour,
  case when least(rnk, 3) < 3 then network else 'All others' end as network,
  sum("total") as "total"
from (
  select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (PARTITION by TIME_FLOOR(__time, 'PT1H') order by count(*) desc) as rnk,
    network,
    count(*) as "total"
  from "test_dev"
  where "network" is not null and "user_id" = 'abcd' and __time BETWEEN TIMESTAMP '2024-05-08 12:00:00' AND TIMESTAMP '2024-05-09 12:00:00'
  group by network, TIME_FLOOR(__time, 'PT1H')
)
group by time_hour, 2
order by time_hour, 3 asc
give below resultset: a customer that submits requests for more than 3 different networks across time period
And this other one:
Copy code
select
  time_hour,
  case when least(rnk, 3) < 3 then network else 'All others' end as network,
  sum("total") as "total"
from (
  select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (PARTITION by TIME_FLOOR(__time, 'PT1H') order by count(*) desc) as rnk,
    network,
    count(*) as "total"
  from "test_dev"
  where "network" is not null and "user_id" = '1234' and __time BETWEEN TIMESTAMP '2024-05-08 12:00:00' AND TIMESTAMP '2024-05-09 12:00:00'
  group by network, TIME_FLOOR(__time, 'PT1H')
)
group by time_hour, 2
order by time_hour, 3 asc
following resultset: a customer that only submits requests to 2 different networks across time period:
however, for the json native query I am getting different timestamp
1715169600000
instead of
2024-05-08T12:00:00.000Z
format, I see I get:
Copy code
"virtualColumns": [
            {
              "type": "expression",
              "name": "v0",
              "expression": "timestamp_floor(\"__time\",'PT1H',null,'UTC')",
              "outputType": "LONG"
            }
          ],
...
"dimensions": [
            {
              "type": "default",
              "dimension": "payload_method",
              "outputName": "d0",
              "outputType": "STRING"
            },
            {
              "type": "default",
              "dimension": "v0",
              "outputName": "d1",
              "outputType": "LONG"
            }
          ],
....
 "outputSignature": [
        {
          "name": "d0",
          "type": "STRING"
        },
        {
          "name": "d1",
          "type": "LONG"
        },
        {
          "name": "a0",
          "type": "LONG"
        },
        {
          "name": "w0",
          "type": "LONG"
        }
      ],
....
"operatorDefinition": [
        {
          "type": "naiveSort",
          "columns": [
            {
              "column": "d1",
              "direction": "ASC"
            },
            {
              "column": "a0",
              "direction": "DESC"
            }
          ]
        },
        {
          "type": "naivePartition",
          "partitionColumns": [
            "d1"
          ]
        },
...
"dimensions": [
    {
      "type": "default",
      "dimension": "d1",
      "outputName": "_d0",
      "outputType": "LONG"
    },
    {
      "type": "default",
      "dimension": "v0",
      "outputName": "_d1",
      "outputType": "STRING"
    }
  ],
  "aggregations": [
    {
      "type": "longSum",
      "name": "_a0",
      "fieldName": "a0"
    }
  ],
  "limitSpec": {
    "type": "default",
    "columns": [
      {
        "dimension": "_d0",
        "direction": "ascending",
        "dimensionOrder": {
          "type": "numeric"
        }
      },
      {
        "dimension": "_a0",
        "direction": "ascending",
        "dimensionOrder": {
          "type": "numeric"
        }
      }
    ],
    "limit": 1001
  },
probably something I need to tweak with
virtualColumns
right?
g
oh, yeah, that's SQL layer magic. in native queries we typically process timestamps as milliseconds since epoch; the SQL layer pretty-prints them when it sends them back to you
you could pretty-print them on your own after retrieving the native query result or, if you need the result to come back pretty-printed, try adding an
expression
post-aggregator at the outermost query that does a
timestamp_format
expression
you can get the SQL planner to write one for you by doing
SELECT TIME_FORMAT(time_hour) …
instead of
SELECT time_hour …
at the first line of your query
j
I thought of processing the query result in code and format it to human readable format.
I also attempted to to time format in the SQL I shared above but I got couple of errors
all right I see, got
Copy code
"postAggregations": [
    {
      "type": "expression",
      "name": "s0",
      "expression": "timestamp_format(\"_d0\",'yyyy-MM-dd\\u0027T\\u0027HH:mm:ss.SSSZZ','UTC')",
      "outputType": "STRING"
    }
  ],
wonder, would this work
TIME_FORMAT(time_hour, 'yyyy-MM-ddTHH:mm:ssZ', 'UTC'),
?
looks like
TIME_FORMAT(time_hour, 'yyyy-MM-ddTHH:mm:ssZ', 'UTC'),
does not work but
TIME_FORMAT(time_hour, 'yyyy-MM-dd HH:mm:ss', 'UTC'),
does
g
i think for
yyyy-MM-ddTHH:mm:ssZ
you need to escape the T and Z
something like
TIME_FORMAT(time_hour, 'yyyy-MM-dd''T''HH:mm:ss''Z''', 'UTC')
j
yep, completely right! had to scape T and Z, thanks!
🙌 1
Wanted to bring back this convo. I have updated supervisors to include `sum_credit_units`:
Copy code
...
"dimensionExclusions": [
          "__time",
          "count",
          "ts",
          "sum_credit_units"
        ],
        "includeAllDimensions": false,
        "useSchemaDiscovery": false
      },
      "metricsSpec": [
        {
          "type": "count",
          "name": "count"
        },
        {
          "type": "longSum",
          "name": "sum_credit_units",
          "fieldName": "credit_units"
        }
      ],
...
It links to how much it costed to user to submit that request to our API, now I want:
Copy code
select
  TIME_FORMAT(time_hour, 'yyyy-MM-dd''T''HH:mm:ss''Z''', 'UTC'),
  case when least(rnk, 5) < 5 then network else 'All others' end as network,
  sum("credits") as "credits"
from (
  select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (PARTITION by TIME_FLOOR(__time, 'PT1H') order by count(*) desc) as rnk,
    network,
    "sum_credit_units" as "credits"
  from "test_dev"
  where "network" is not null and "user_id" = 'abcd' and __time BETWEEN TIMESTAMP '2024-05-23 15:27:00' AND TIMESTAMP '2024-05-24 15:27:00'
  group by network, TIME_FLOOR(__time, 'PT1H'), sum_credit_units
)
group by time_hour, 2
order by time_hour, 3 asc
but I am not sure if it is right, since the result set I got for
All Others
is too high (173785) and in dev there is no much going on, not sure if the query is right
Perhaps you can help me again Gian, before we were looking at building queries taking into account
count
metric, but what I was really after was another metric (shared above
sum_credit_units
)
Copy code
select
  TIME_FORMAT(time_hour, 'yyyy-MM-dd''T''HH:mm:ss''Z''', 'UTC'),
  case when least(rnk, 5) < 5 then "payload_method" else 'All others' end as payload_method,
  sum("credits") as "credits"
from (
 select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (PARTITION by TIME_FLOOR(__time, 'PT1H') order by count(*) desc) as rnk,
    payload_method,
    "sum_credit_units" as "credits"
  from "test_dev"
  where "payload_method" is not null and "user_id" = 'abcd' and __time BETWEEN TIMESTAMP '2024-05-27 09:00:00' AND TIMESTAMP '2024-05-28 09:00:00'
  group by payload_method, TIME_FLOOR(__time, 'PT1H'), sum_credit_units
)
group by time_hour, 2
order by time_hour, 3 asc
above query give me this result: but I know it is wrong since for a given day and hour I have total
1506712
count (2024-05-27T090000Z). Currently
credit_units
is 1 for every row. Not sure if I am missing something
and I have this query too:
Copy code
select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (PARTITION by TIME_FLOOR(__time, 'PT1H') order by count(*) desc) as rnk,
    payload_method,
    sum("sum_credit_units") as "credits"
  from "test_dev"
  where "payload_method" is not null and "user_id" = 'abcd' and __time BETWEEN TIMESTAMP '2024-05-27 09:00:00' AND TIMESTAMP '2024-05-28 09:00:00'
  group by payload_method, TIME_FLOOR(__time, 'PT1H')
that give me below: so it is a matter of combining to get the
All Others
thing but cant make it work
Actually not sure if this should do the trick:
Copy code
select
  TIME_FORMAT(time_hour, 'yyyy-MM-dd''T''HH:mm:ss''Z''', 'UTC'),
  case when least(rnk, 5) < 5 then "payload_method" else 'All others' end as payload_method,
  sum("credits") as "credits"
from (
select
    TIME_FLOOR(__time, 'PT1H') as time_hour,
    RANK() over (PARTITION by TIME_FLOOR(__time, 'PT1H') order by count(*) desc) as rnk,
    payload_method,
    sum("sum_credit_units") as "credits"
  from "test_dev"
  where "payload_method" is not null and "user_id" = 'abcd' and __time BETWEEN TIMESTAMP '2024-05-27 09:00:00' AND TIMESTAMP '2024-05-28 09:00:00'
  group by payload_method, TIME_FLOOR(__time, 'PT1H')
)
group by time_hour, 2
order by time_hour, 3 asc
g
wondering if you did end up figuring this out? i was too busy last week to check slack much
j
Yeah I think we got it right, however we were not sure if we should have the rack per bucket window or whole period, so in above query I have
RANK() over (PARTITION by TIME_FLOOR(__time, 'PT1H') order by count(*) desc) as rnk,
in the inner query, giving it for each 1h bucket in the whole 24h period, but not sure if we should have the
All Others
aggregated in the 24h period instead of 1h bucket windows, an not sure if possible at all