Standard funnel analysis treats all users as a single group. When you need to compare conversion rates across user segments — such as by province, acquisition channel, or device type — use finder_group_funnel to split funnel results by a TEXT dimension field.
Each user is assigned to exactly one group based on the dimension value present at the grouping event. Users who do not reach the grouping event, or whose dimension value does not match any group, are assigned to the built-in unreach group.
The function returns a BINARY-encoded result per user per group. To extract usable data, decode the output using two companion functions:
finder_group_funnel_res— decodes each user's per-step funnel progressfinder_group_funnel_text_group— decodes the group label (dimension value orunreach)
To aggregate per-user results into group-level conversion counts, pass the decoded output to funnel_rep.
Prerequisites
Before you begin, ensure that you have:
Hologres V2.2.32 or later
Superuser access to the target database
Install the extension
Run the following statement as a superuser to install the flow_analysis extension:
CREATE extension flow_analysis; -- Install the extension.The extension is installed at the database level. Install it only once per database.
By default, the extension loads into the public schema and cannot be loaded into other schemas. To call functions from a different schema, use the public.function_name format — for example, public.windowFunnel.
How it works
finder_group_funnel processes events in three stages:
Slot assignment — For each event row,
server_timestampdetermines which step slot (day, hour, or other interval) the event belongs to.Sorting — Within each slot, events are sorted by
client_timestampto establish the sequence.Grouping and tracking — Starting at
group_event_index, users are assigned to a group based on theirgroup_dimensionvalue. The function then tracks each user's progress through the orderedcheck_eventlist within thewindowduration.
The result is a BINARY-encoded value per user per group. Pipe the output through finder_group_funnel_res and finder_group_funnel_text_group to read funnel progress and group labels.
finder_group_funnel
Groups events by the specified dimension and calculates per-user funnel results.
Syntax
finder_group_funnel(
window,
start_timestamp,
step_interval,
step_numbers,
num_events,
attr_related,
group_event_index,
time_zone,
is_relative_window,
server_timestamp,
client_timestamp,
group_dimension,
[prop1, prop2, ...],
check_event1, check_event2, ...
)Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
window | Yes | — | Size of the analysis window. Unit: milliseconds. |
start_timestamp | Yes | TIMESTAMP / TIMESTAMPTZ | Start time of the analysis. |
step_interval | Yes | — | Duration of one step (the granularity of conversion analysis). Unit: seconds. For example, 86400 = one day. |
step_numbers | Yes | — | Number of steps to analyze. For example, step_interval=86400 and step_numbers=7 means the function analyzes daily funnel data for 7 days starting from start_timestamp. |
num_events | Yes | — | Total number of events to track in the funnel. |
attr_related | Yes | UINT8 | Indicates which events have associated properties. In binary form, if the ith bit is 1, the (i+1)th event has associated properties. The number of prop expressions must equal the number of 1-bits. Set to 0 if no event has associated properties. |
group_event_index | Yes | — | The event at which grouping begins. If set to 1, users are grouped as soon as they complete the first event. If set to 2, grouping starts at the second event — users who do not reach the second event are assigned to the unreach group. |
time_zone | Yes | TEXT | Time zone of the input timestamps, in standard format (for example, Asia/Shanghai). This parameter only affects output when is_relative_window is true. |
is_relative_window | Yes | BOOLEAN | Whether to use calendar-day boundaries instead of a fixed duration window. Default: false. When set to true: window must be an integer multiple of 86,400,000, and step_interval must be 86400. See the Calendar-day window section below for details. |
server_timestamp | Yes | TIMESTAMP / TIMESTAMPTZ | Server-side event time. Used to determine which step slot each event belongs to. |
client_timestamp | Yes | TIMESTAMP / TIMESTAMPTZ | Client-side event time. Must match the data type of start_timestamp. Used to sort events. |
group_dimension | Yes | TEXT | The field to group by. Only TEXT fields are supported. To group by multiple fields, combine them with concat_ws or concat. |
prop | No | — | Associated properties for events with attr_related bits set to 1. All prop expressions must have the same data type. |
check_event | Yes | — | Ordered list of conversion events. Events that match within the window duration count as valid conversions. Example: event = 'E0001', event = 'E0002', event = 'E0003'. |
Calendar-day window
When is_relative_window=true, the window uses calendar-day boundaries rather than a fixed elapsed duration:
A calendar day runs from
00:00:00to23:59:59.The first day spans from the event time to
23:59:59on the same day.Each subsequent day is a full calendar day.
Use calendar-day windows when funnel reporting periods must align to business days (midnight to midnight) rather than rolling 24-hour intervals from the first event.
Return value
An encoded result of type BINARY. Decode it with finder_group_funnel_res and finder_group_funnel_text_group.
Example
The following example groups funnel results by province over a 3-day window. User 1111 is from Beijing and user 2222 is from Zhejiang.
Step 1: Create the test table and insert data.
CREATE TABLE finder_group_funnel_test(
id INT,
event_time TIMESTAMP,
event TEXT,
province TEXT,
city TEXT
);
INSERT INTO finder_group_funnel_test VALUES
(1111, '2024-01-02 00:00:00', 'registration', 'Beijing', 'Beijing'),
(1111, '2024-01-02 00:00:01', 'logon', 'Beijing', 'Beijing'),
(1111, '2024-01-02 00:00:02', 'payment', 'Beijing', 'Beijing'),
(1111, '2024-01-02 00:00:03', 'exit', 'Beijing', 'Beijing'),
(1111, '2024-01-03 00:00:00', 'registration', 'Beijing', 'Beijing'),
(1111, '2024-01-03 00:00:01', 'logon', 'Beijing', 'Beijing'),
(1111, '2024-01-03 00:00:02', 'payment', 'Beijing', 'Beijing'),
(1111, '2024-01-04 00:00:00', 'registration', 'Beijing', 'Beijing'),
(1111, '2024-01-04 00:00:01', 'logon', 'Beijing', 'Beijing'),
(2222, '2024-01-02 00:00:00', 'registration', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:00', 'logon', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:01', 'payment', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:03', 'payment', 'Zhejiang', 'Hangzhou');Step 2: Group results by province over a 3-day window.
SELECT
id,
UNNEST(
finder_group_funnel(
86400000 * 3, -- 3-day window
EXTRACT(epoch FROM TIMESTAMP '2024-01-02 00:00:00')::BIGINT,
86400, -- step_interval: 1 day
3, -- step_numbers: 3 days
4, -- num_events: 4 events
0, -- attr_related: no associated properties
1, -- group_event_index: group on first event
'Asia/Shanghai',
FALSE,
event_time,
event_time,
province, -- group_dimension
event = 'registration',
event = 'logon',
event = 'payment',
event = 'exit'
)
) AS result
FROM finder_group_funnel_test
GROUP BY id;The result is BINARY-encoded. Each row shows the user ID and their group label (province value or unreach):
id | result
------+---------
2222 | Zhejiang
2222 | unreach
1111 | Beijing
1111 | unreach
(4 rows)To decode the detailed funnel progress for each group, use finder_group_funnel_res.
finder_group_funnel_res
Decodes the BINARY result from finder_group_funnel into per-user funnel details for each step.
Syntax
finder_group_funnel_res(finder_group_funnel(...))Parameters
| Parameter | Description |
|---|---|
finder_group_funnel() | The BINARY result from finder_group_funnel. |
Return value
An integer array showing the furthest event reached in the overall window and in each step interval.
Example
Using the table from the finder_group_funnel example, decode each user's per-day funnel progress:
SELECT
id,
finder_group_funnel_res(result) AS res
FROM (
SELECT
id,
UNNEST(
finder_group_funnel(
86400000 * 3,
EXTRACT(epoch FROM TIMESTAMP '2024-01-02 00:00:00')::BIGINT,
86400, 3, 4, 0, 1, 'Asia/Shanghai', FALSE,
event_time, event_time,
province,
event = 'register',
event = 'logon',
event = 'pay',
event = 'exit'
)
) AS result
FROM finder_group_funnel_test
GROUP BY id
) a;Result:
id | res
------+-----------
1111 | {4,4,3,2}
1111 | {0,0,0,0}
2222 | {3,3,0,0}
2222 | {0,0,0,0}Reading the result array: Each array has 1 + step_numbers elements. The first element is the furthest event reached across the entire window; the remaining elements are the furthest event reached within each step interval (day, in this case).
For user 1111 with result {4,4,3,2}:
| Position | Value | Meaning |
|---|---|---|
| Overall (3-day window) | 4 | Reached the 4th event (exit) within 3 days |
| Day 1 | 4 | Reached exit on day 1 |
| Day 2 | 3 | Reached the 3rd event (payment) on day 2 |
| Day 3 | 2 | Reached the 2nd event (logon) on day 3 |
finder_group_funnel_text_group
Decodes the group label (dimension value or unreach) from the BINARY result. Use it alongside finder_group_funnel_res to get both the group name and the funnel data in one query.
Syntax
finder_group_funnel_text_group(finder_group_funnel(...))Parameters
| Parameter | Description |
|---|---|
finder_group_funnel() | The BINARY result from finder_group_funnel. |
Return value
The decoded group label as text — the dimension value (for example, Beijing) or unreach.
Example
The following query decodes both the group label and per-day funnel progress in a single pass:
SELECT
id,
finder_group_funnel_text_group(result) AS key,
finder_group_funnel_res(result) AS res
FROM (
SELECT
id,
UNNEST(
finder_group_funnel(
86400000 * 3,
EXTRACT(epoch FROM TIMESTAMP '2024-01-02 00:00:00')::BIGINT,
86400, 3, 4, 0, 1, 'Asia/Shanghai', FALSE,
event_time, event_time,
province,
event = 'registration',
event = 'logon',
event = 'payment',
event = 'exit'
)
) AS result
FROM finder_group_funnel_test
GROUP BY id
) a;Result:
id | key | res
------+----------+-----------
2222 | Zhejiang | {3,3,0,0}
2222 | unreach | {0,0,0,0}
1111 | Beijing | {4,4,3,2}
1111 | unreach | {0,0,0,0}
(4 rows)funnel_rep
Aggregates per-user funnel results (from finder_group_funnel_res) into group-level conversion counts at each funnel step.
Syntax
funnel_rep(step_number, num_events, funnel_res)Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
step_number | Yes | UINT | Number of time slots. Typically the same as step_numbers in finder_group_funnel. |
num_events | Yes | UINT | Total events in the funnel. Typically the same as the number of check_event expressions. |
funnel_res | Yes | — | Per-user conversion step details generated by each user, which is the output of finder_group_funnel or FINDER_FUNNEL. |
Return value
A string array in the format {"overall","step1","step2",...}. Each element is a comma-separated list of user counts that reached events 1 through N:
The first element is the overall count across the full window.
Each subsequent element is the count within that step interval.
Example
Using the data from the finder_group_funnel example, calculate how many users reached each event across a 3-day window with a 1-day step:
-- 3-day window, 1-day step: count users reaching each event per day.
SELECT
funnel_rep(3, 4, funnel_res)
FROM (
SELECT
id,
FINDER_FUNNEL(
86400000 * 3,
EXTRACT(epoch FROM TIMESTAMP '2024-01-02 00:00:00')::BIGINT,
86400, 3, 4, 0, 'Asia/Shanghai', FALSE,
event_time, event_time,
event = 'registration',
event = 'logon',
event = 'payment',
event = 'exit'
) AS funnel_res
FROM finder_group_funnel_test
GROUP BY id
) a;Result:
funnel_rep
-------------------------------------------
{"2,2,2,1","2,2,2,1","1,1,1,0","1,1,0,0"}
(1 row)Reading this result with step_numbers=3 and num_events=4:
| Element | Value | Meaning |
|---|---|---|
| Overall | 2,2,2,1 | Across 3 days: 2 users reached event 1, 2 reached event 2, 2 reached event 3, 1 reached event 4 |
| Day 1 | 2,2,2,1 | On day 1: same pattern |
| Day 2 | 1,1,1,0 | On day 2: 1 user reached events 1–3, none reached event 4 |
| Day 3 | 1,1,0,0 | On day 3: 1 user reached events 1–2, none reached events 3–4 |
Complete examples
Scenario 1: Group funnel results by dimension over a multi-day window
Goal: An e-commerce team wants to compare how users from Beijing, Shanghai, and Zhejiang convert through a 4-step flow (registration → logon → payment → exit) within a 3-day rolling window, with daily breakdowns. The team expects Beijing users to show the highest completion rate across all days.
Step 1: Create the test table and insert data.
CREATE TABLE finder_group_funnel_test_1(
id INT,
event_time TIMESTAMP,
event TEXT,
province TEXT,
city TEXT
);
INSERT INTO finder_group_funnel_test_1 VALUES
(1111, '2024-01-02 00:00:00', 'registration', 'Beijing', 'Beijing'),
(1111, '2024-01-02 00:00:01', 'logon', 'Beijing', 'Beijing'),
(1111, '2024-01-02 00:00:02', 'payment', 'Beijing', 'Beijing'),
(1111, '2024-01-02 00:00:03', 'exit', 'Beijing', 'Beijing'),
(1111, '2024-01-03 00:00:00', 'registration', 'Beijing', 'Beijing'),
(1111, '2024-01-03 00:00:01', 'logon', 'Beijing', 'Beijing'),
(1111, '2024-01-03 00:00:02', 'payment', 'Beijing', 'Beijing'),
(1111, '2024-01-04 00:00:00', 'registration', 'Beijing', 'Beijing'),
(1111, '2024-01-04 00:00:01', 'logon', 'Beijing', 'Beijing'),
(2222, '2024-01-02 00:00:00', 'registration', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:00', 'logon', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:01', 'payment', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:03', 'payment', 'Zhejiang', 'Hangzhou'),
(3333, '2024-01-02 00:00:00', 'registration', 'Shanghai', 'Shanghai'),
(3333, '2024-01-02 00:00:00', 'logon', 'Shanghai', 'Shanghai'),
(3333, '2024-01-02 00:00:01', 'payment', 'Shanghai', 'Shanghai'),
(3333, '2024-01-02 00:00:03', 'payment', 'Shanghai', 'Shanghai'),
(3333, '2024-01-02 00:00:04', 'exit', 'Shanghai', 'Shanghai');Step 2: Query daily funnel data grouped by province.
SELECT
key,
funnel_rep(3, 4, res) AS ans
FROM (
SELECT
id,
finder_group_funnel_text_group(result) AS key,
finder_group_funnel_res(result) AS res
FROM (
SELECT
id,
UNNEST(
finder_group_funnel(
86400000 * 3,
EXTRACT(epoch FROM TIMESTAMP '2024-01-02 00:00:00')::BIGINT,
86400, 3, 4, 0, 1, 'Asia/Shanghai', FALSE,
event_time, event_time,
province,
event = 'Register',
event = 'Log on',
event = 'Payment',
event = 'Exit'
)
) AS result
FROM finder_group_funnel_test_1
GROUP BY id
) a
) b
GROUP BY key;Result:
key | ans
----------+-------------------------------------------
Beijing | {"1,1,1,1","1,1,1,1","1,1,1,0","1,1,0,0"}
unreach | {"0,0,0,0","0,0,0,0","0,0,0,0","0,0,0,0"}
Shanghai | {"1,1,1,1","1,1,1,1","0,0,0,0","0,0,0,0"}
Zhejiang | {"1,1,1,0","1,1,1,0","0,0,0,0","0,0,0,0"}
(4 rows)Beijing's user completed all 4 events on day 1 and continued converting on days 2 and 3. Shanghai's user also completed all 4 events but only on day 1 (no follow-up activity). Zhejiang's user reached only 3 of 4 events.
Scenario 2: Group funnel results by calendar day
Goal: The same team wants to observe funnel data aligned to calendar-day boundaries (midnight to midnight) rather than a rolling elapsed-time window. This matches how business reporting periods are typically defined. With a rolling window, the exit event on 2024-01-05 might still fall within 3 days of the first event; with calendar-day boundaries, it does not.
Step 1: Create the test table and insert data.
CREATE TABLE finder_group_funnel_test_2(
id INT,
event_time TIMESTAMP,
event TEXT,
province TEXT,
city TEXT
);
INSERT INTO finder_group_funnel_test_2 VALUES
(1111, '2024-01-02 00:00:02', 'registration', 'Beijing', 'Beijing'),
(1111, '2024-01-02 00:00:03', 'logon', 'Beijing', 'Beijing'),
(1111, '2024-01-03 00:00:04', 'payment', 'Beijing', 'Beijing'),
(1111, '2024-01-05 00:00:01', 'exit', 'Beijing', 'Beijing'),
(2222, '2024-01-02 00:00:00', 'registration', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:00', 'logon', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:01', 'payment', 'Zhejiang', 'Hangzhou'),
(2222, '2024-01-02 00:00:03', 'payment', 'Zhejiang', 'Hangzhou');Step 2: Query with calendar-day boundaries (`is_relative_window=TRUE`).
SELECT
key,
funnel_rep(3, 4, res) AS ans
FROM (
SELECT
id,
finder_group_funnel_text_group(result) AS key,
finder_group_funnel_res(result) AS res
FROM (
SELECT
id,
UNNEST(
finder_group_funnel(
86400000 * 3,
EXTRACT(epoch FROM TIMESTAMP '2024-01-02 00:00:00')::BIGINT,
86400, 3, 4, 0, 1, 'Asia/Shanghai', TRUE, -- calendar-day window
event_time, event_time,
province,
event = 'register',
event = 'logon',
event = 'pay',
event = 'exit'
)
) AS result
FROM finder_group_funnel_test_2
GROUP BY id
) a
) b
GROUP BY key;Result:
key | ans
----------+-------------------------------------------
unreach | {"0,0,0,0","0,0,0,0","0,0,0,0","0,0,0,0"}
Zhejiang | {"1,1,1,0","1,1,1,0","0,0,0,0","0,0,0,0"}
Beijing | {"1,1,1,0","1,1,1,0","0,0,0,0","0,0,0,0"}
(3 rows)With calendar-day boundaries, user 1111 (Beijing) completes only 3 of 4 events within the 3-day window. Their exit event occurs on 2024-01-05, which falls outside the calendar-day window starting 2024-01-02 (covering January 2, 3, and 4). Under a rolling window, the same event would be captured because it falls within 3 × 86,400 seconds of the first event.
Limitations
| Limitation | Details |
|---|---|
| Version requirement | Only Hologres V2.2.32 and later support finder_group_funnel. |
group_dimension field type | Only TEXT fields are supported. To group by multiple fields, use concat_ws or concat. |
| Calendar-day window constraints | When is_relative_window=true, window must be an integer multiple of 86,400,000 and step_interval must be 86400. |
| Extension schema | The flow_analysis extension loads into the public schema only and cannot be loaded into other schemas. |