Reporting Data Model
Introduction
The N2ACD reporting database complements the real-time N2ACD SMS database by providing the following information:
- Per-ACD call summary data, summarised from individual EDRs generated.
- N2ACD SMS data, copied from the SMS database at a point in time.
All database tables referenced can be found in the n2reporting
database of
N2ACD. Depending on the deployment model, this database will be co-located
on the reporting application node, or hosted on separate database servers.
The n2reporting
database is a PostgreSQL database. All N2ACD reporting
tables are created in the n2acd
database schema. If other N-Squared products
are installed and use the same reporting node, they will have their own
schema.
EDR Database Tables
N2ACD_EDR
The n2acd.n2acd_edr
table stores the EDRs in a JSON format closely
aligned with the raw text EDR format. EDRs generated by real-time platform
(whether from ACD, or the SRF) and determined to be for the ACD service will
be present in this table.
This table is partitioned.
Column Name | Type | Purpose |
---|---|---|
event_timestamp | timestamp | The time the event occurred and was processed by N2SVCD. This is not the time the EDR was loaded into the reporting database. If SIP EDRs are merged (using the sip_merge_edr flag), this will be the value of the REQUEST_AT field of that EDR. |
session_id | text | The session ID as provided by n2svcd. This will be a long text string and may not be unique. |
first_instance_guid | text | The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for. |
type | text | The type of EDR, indicating whether this is a INAP, SIP or ACD EDR, or any other sort of EDR. |
edr | JSON | A postgres JSON field that gives the EDR content as key/value pairs. |
edr_content_checksum | bigint | The CRC32 checksum of the original EDR string. This will be provided by NiFi to PostgreSQL as part of the store process. |
insert_collisions | smallint | A counter that tracks the number of times this EDR was inserted into the database. The data processing pipeline is designed to support replaying data processing even in the case the data already exists. This column is a simple tracking mechanism for tracking whether an EDR has been processed multiple times. |
creation_date | timestamp | When this record was first created in the database. This is an auditing field and determines the time delay between the EDR event timestamp, and the date/time it was inserted into the database. |
A session_id
is a long string that determines the n2svcd
processes involved in the session that generates the EDR. Taking an EDR such as:
2022-05-15 21:30:47.948<6cb1eb0b47dc~SIGTRAN~1652650168~7f16d4a4,6cb1eb0b47dc~ACD SCP~1652650168~0b960fef,6cb1eb0b47dc~ACD Logic~1652650168~0b8a08fb>ACD|CUST_ID=7|CUST_NAME=Test Set 2 0800100100 Customer|FLOW_ID=8|FLOW_NAME=Test Set 2 0800100100 Flow|FLOW_VERSION=1|NODES=AT-1
The EDR is broken down as follows:
event_timestamp
will be2022-05-15 21:30:47.948
session_id
will be6cb1eb0b47dc~SIGTRAN~1652650168~7f16d4a4,6cb1eb0b47dc~ACD SCP~1652650168~0b960fef,6cb1eb0b47dc~ACD Logic~1652650168~0b8a08fb
first_instance_guid
will be6cb1eb0b47dc~SIGTRAN~1652650168~7f16d4a4
type
will beACD
edr
will be the rest of the EDR after the type, broken down into key = value pairs and stored as JSON (note that any structured data within a value will not be broken down further).edr_content_checksum
will be 0x76ae7902.
SUMMARISED_EDR
The n2acd.summarised_edr
table aggregates information from multiple EDRs to give
a single view of a single voice call made to a service number.
This table is partitioned.
Column Name | Type | Purpose |
---|---|---|
call_id | text | This is the instance ID of the N2SVCD “SCP” or “SIP” app that handled the call. It matches the last part of the session ID from the InitialDP (or INVITE) EDR related to this call. |
called | text | The service number dialled by the caller, normalised by the real time call control layer of N2ACD. |
calling | text | The calling party, normalised by the real time call control player of N2ACD. |
calling_presentation_restricted | boolean | If true, the calling party number should be considered presentation restricted (i.e. not shared). |
completion_state | text | A simple flag - one of abandon , answer , decline , hangup , problem , release or unconditional that indicates how the call ended. See the related documentation for more information on each state. |
creation_date | timestamp | When this record was first created in the database. This is an auditing field and determines how long after the first EDR from the call was processed. |
cust_id | integer | The N2ACD customer ID, for the record in the N2ACD database of the customer that owned the service number at the time the call was made. |
decline_code | integer | Defines how the call ended toward the A party if the call did not end with an A - B party connection. This is also used for the release call ‘cause’ field from INAP. It is not nessarily the same as the last decline code returned when attempting a B party connection. |
executed_node_list | JSON | The list of nodes that were processed as part of the call this EDR represents. This is a JSON array, with each element of the array being a map of the form {"id": "1", "exit": 2, "type": "KEY" } where KEY is the node type key, id is the ID of the node in the operations map as shown in the screens, and exit is the one-based index index taken by the node (the first exit of the node is exit 1). |
first_event_timestamp | timestamp | The time that the first event could be found related to this ACD voice call. This will be the event_timestamp of the earliest EDR seen with the given first_instance_guid. |
first_instance_guid | text | The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for. This is a correlation field to use when correlating with the n2acd_edr table. |
flow_id | integer | The ID of the flow used to execute this call. |
flow_name | text | The name of the flow used to execute this call - as given by the EDR. |
last_event_timestamp | timestamp | The date/time of the last EDR that was matched to this record. This will always be the latest date/time seen - not the date/time of the latest EDR processed. |
last_updated | timestamp | The timestamp for the last time this summarised EDR record was updated. |
service | text | The service the EDR is for. For ACD calls, this is ACD . If EDR processing captures an EDR stream for a call scenario that is not handled by ACD (e.g. a freephone call that was received for a ported number, and hence triggered a port-out response, not an ACD processing response) this field will not be set, or set to a value other than ACD (e.g. ACD-NP ). |
service_node | text | The hostname, as given by the ACD EDR that handled the call. |
talk_dsm | integer | The call talk time, as calculated by the service. This is the time the caller spent on the line talking (after the all is answered). |
SUMMARISED_EDR_HOLDING
The n2acd.summarised_edr_holding
table is structured exactly the same as the SUMMARISED_EDR
table. It is used for the storage of EDRs that are not yet considered complete. EDRs are transferred from SUMMARISED_EDR_HOLDING
to SUMMARISED_EDR
automatically once they are considered completed.
To query both tables and retrieve a single view of all summarised EDRs, use the view n2acd.gather_summarised_edrs
.
SUMMARISED_EDR_B_PARTY
The n2acd.summarised_edr_b_party
table lists key information
for every B-party interaction event captured by an EDR - such
as attempt terminate requests, and answer requests.
This table is partitioned.
Column Name | Type | Purpose |
---|---|---|
event_timestamp | timestamp | The time the event occurred and was processed by N2SVCD. This is not the time the EDR was loaded into the reporting database. If SIP EDRs are merged (using the sip_merge_edr flag), this will be the value of the REQUEST_AT field of that EDR. |
first_instance_guid | text | The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for. This is a correlation field to use when correlating with the summarised_edr and n2acd_edr tables. |
dra | text | The destination address (phone number/SIP URI) that was attempted during an attempt termination request. If this is not null, then decline_code will be null |
decline_code | text | The result of the last attempt terminate. This will be a SCP BCSM event such as oCalledPartyBusy_leg2 , oNoAnswer_leg2 , oAbandon_leg1 , or routeSelectFailure_leg2 . SIP events are similar. If this is not null, then dra will be null. |
To connect records in this table, it is important to order by the event_timestamp
and link the record with the DRA with the record with the decline_code
(if there is one). For example, the following query will list each EDR from the summarised_edr
table and each attempted connection to a b-party:
with bparty_info AS (
SELECT DISTINCT
edrs.first_instance_guid
, rank() OVER (PARTITION BY edrs.first_instance_guid ORDER BY event_timestamp DESC) AS rank
, dra
, b.decline_code
, completion_state
FROM
n2acd.summarised_edr edrs
JOIN n2acd.summarised_edr_b_party b USING (first_instance_guid)
),
bparties AS (
SELECT
first_instance_guid
, rank() OVER (PARTITION BY first_instance_guid ORDER BY rank ASC) AS rank
, rank() OVER (PARTITION BY first_instance_guid ORDER BY rank DESC) AS counter
, rank AS old_rank
, dra
, completion_state
FROM
bparty_info
WHERE
dra IS NOT NULL
),
last_bparty AS (
SELECT
bparties.first_instance_guid
, bparties.counter
, bparties.dra
-- The result of the call. We use the DRA decline code in preference.
-- "No_Answer" if the network indicated that the no answer timer fired.
-- "Busy" if the network reported a busy event.
-- "Abandon" if the caller hung up before the call was answered.
-- "Answer" if the network reported that the call was answered.
-- "Disconnect" if the last interaction in the call was an announcement
-- "Other" otherwise.
, (CASE
when decline_code = 'oCalledPartyBusy_leg2' THEN 'Busy'
when decline_code = 'oNoAnswer_leg2' THEN 'No_Answer'
when decline_code = 'routeSelectFailure_leg2' THEN 'Other'
when bparties.completion_state = 'abandon' THEN 'Abandon'
when bparties.completion_state = 'answer' THEN 'Answer'
when bparties.completion_state = 'release' THEN 'Disconnect'
else 'Other'
END) as completion_state
FROM
bparties
LEFT JOIN bparty_info bparty_resp ON bparties.first_instance_guid = bparty_resp.first_instance_guid AND bparties.old_rank = bparty_resp.rank + 1 AND bparty_resp.DRA IS NULL
WHERE
bparties.rank = 1
)
SELECT * FROM last_bparty;
SUMMARISED_EDR_SRP_INTERACTIONS
The n2acd.summarised_edr_srp_interactions
table lists key information
for every SRF interaction event captured by an EDR.
This table is partitioned.
Column Name | Type | Purpose |
---|---|---|
event_timestamp | timestamp | The time the event occurred and was processed by N2SVCD. This is not the time the EDR was loaded into the reporting database. If SIP EDRs are merged (using the sip_merge_edr flag), this will be the value of the REQUEST_AT field of that EDR. |
first_instance_guid | text | The first segment of the session ID that represents the application and application session ID that first handled the session the EDR is for. This is a correlation field to use when correlating with the summarised_edr and n2acd_edr tables. |
digits | text | If the SRF interaction requested user input, this field captures the digits input by the user. In the case where the user input was for an ACD PIN node, this field will store ? not the actual input digits. |
error | text | If the source EDR captures an error during the user interaction (e.g. the user didn’t input a value correctly) this field captures that error. |
message_ids | integer array | A list of message IDs requested for to be played by ACD. This is the INAP message_ids list, not a list of files played by the SRF. |
event | text | One of response , prompt , or play . If response then digits or error will be non-null. The prompt and play distinguish between different interaction requests. |
To connect records in this table, it is important to order by the event_timestamp
and link the record with the prompt
or play
with the subsequent response
record. For example, the following query will list each EDR from the summarised_edr
table with a summarised SRP interaction string:
WITH srp_details AS (
SELECT
i.first_instance_guid,
event_timestamp,
i.event,
rank() over (partition by i.first_instance_guid order by event_timestamp) AS r,
CASE
WHEN event = 'prompt' THEN array_to_string(message_ids, ',') || '^'
WHEN event = 'play' THEN array_to_string(message_ids, ',')
ELSE (
CASE
WHEN digits IS NOT NULL AND digits != '' THEN replace(digits, '?', '*')
WHEN error ilike 'abandoned' THEN 'Z'
WHEN error is not null THEN 'X'
ELSE ''
END
)
END AS prompt
FROM
n2acd.summarised_edr_srp_interactions i
), srp_details_linked AS (
SELECT
req.first_instance_guid,
req.event_timestamp,
CASE
WHEN resp.prompt IS NULL THEN req.prompt
-- this here ensures we don't get ^ - i.e. we indicate no entry of digits, with ^X, which
-- respects the requirements of the report
WHEN RIGHT(req.prompt, 1) = '^' AND resp.prompt = '' THEN req.prompt || 'X'
ELSE req.prompt || resp.prompt
END AS prompt
FROM
(SELECT * FROM srp_details WHERE event != 'response') req
LEFT JOIN (SELECT * FROM srp_details WHERE event = 'response') resp ON req.first_instance_guid = resp.first_instance_guid AND resp.r = req.r + 1
)
SELECT
l.first_instance_guid,
STRING_AGG(prompt, ',' ORDER BY event_timestamp) AS interaction
FROM
srp_details_linked l
GROUP BY
l.first_instance_guid;
N2ACD Service Data
If the report extraction process is installed and enabled, the reporting database will store copies of service data as point-in-time extracts from the SMS service database.
Each extract from the N2ACD SMS service database is tagged with a consistent
nifi_insert_timestamp
field. For each extract run, the value of this field is
the same across all database tables.
CUSTOMER
- Table
customer
- View
latest_customer
The customer
table stores data on each N2ACD Customer and is derived from the
n2acd.customer
database table. The view latest_customer
provides only the
data from the latest extract.
Column Name | Type | Purpose |
---|---|---|
nifi_insert_timestamp | timestamp | The date/time the service data was extracted. |
customer_id | integer | The unique ID of the customer. Matches the EDR field CUST_ID |
parent_customer_id | integer | An optional reference to the parent customer of this customer, if this customer is not a top level customer. |
customer_name | text | The unique name of the customer. |
customer_reference | text | The non-unique customer reference. This may be null. |
are_services_disabled | boolean | If all service numbers for the customer are disabled, this will be true. Normally this is false. |
are_service_schedules_overridden | boolean | If this field is true, and the field service.schedule_override_flow_id is set for a service number for this customer, then that override flow will be active for that service. |
are_alternative_termination_numbers_active | boolean | If the customer has an alternative number set, and this boolean flag is true, then those alternative numbers are active. |
profile | JSON | The customer’s profile. |
SERVICE
- Table
customer
- View
latest_service
The service
table stores data on each N2ACD service number and is derived from the
n2acd.service
database table. The latest_service
view is all the data extracted
in the latest extract by NiFi.
Column Name | Type | Purpose |
---|---|---|
nifi_insert_timestamp | timestamp | The date/time the service data was extracted. |
service_id | integer | The unique ID of the service. |
customer_id | integer | The unique ID of the customer the service currently belongs to. |
digits | text | The freephone service number. |
is_disabled | boolean | If true, this service number is disabled and calls to it will be rejected by the platform. |
is_schedule_overridden | boolean | If this field is true, and the field schedule_override_flow_id is set for this service number , then that override flow will be active for that service. |
bar_payphone_callers | boolean | If this field is true, any calls made from payphones to this service number will be rejected. |
bar_cellphone_callers | boolean | If this field is true, any calls made from cellphones to this service number will be rejected. |
follow_me_number | text | If this service number has a follow me number, this will not be null. |
toll_free_beeps_required | boolean | If this service number has the Toll Free Beeps flag set, this will be true. |
pin | text | The PIN for the service number (for self service via management systems). This may be null. |
ignore_barring_list | boolean | If true, the barring list (whether acting as a whitelist or blacklist) for the service number will actually be ignored. |
allow_barring_list_digits | boolean | If true, the barring list will act as a whitelist, not a blacklist. |
profile | JSON | The service’s profile. |
FLOW
- Table
flow
- View
latest_flow
The flow
table stores data on each N2ACD flow and is derived from the
n2acd.flow
database table. A flow itself does not hold much information -
the actual flow design is stored on the flow_version
table. The flow
table is effectively only a name.
The latest_flow
view is all the flows from the last NiFi extract.
Column Name | Type | Purpose |
---|---|---|
nifi_insert_timestamp | timestamp | The date/time the service data was extracted. |
flow_id | integer | The unique ID of the flow. |
flow_name | text | The unique name for the flow (within the customer’s flow list). |
customer_id | integer | The unique ID of the customer the flow currently belongs to. |
external_id | integer | For external management systems, this external_id field defines a unique ID (within the customer’s flow list) by which this flow can be referred. |
FLOW_VERSION
- Table
flow_version
- View
latest_flow_version
The flow_version
table stores data on each N2ACD flow version and is derived
from the n2acd.flow_version
database table. The latest_flow_version
view is all
the flow data from the last NiFi extract.
Column Name | Type | Purpose |
---|---|---|
nifi_insert_timestamp | timestamp | The date/time the service data was extracted. |
flow_version_id | integer | The unique ID of the flow version. |
flow_json | JSON | The JSON definition of the operations of the flow. |
version | integer | The version number (starting from 1 and incrementing on each saved flow version) of the flow version. |
flow_id | integer | The ID of the flow that this JSON is for. |
FLOW_VERSION_SCHEDULE
- Table
flow_version_schedule
- View
latest_flow_version_schedule
The flow_version_schedule
table stores data on each schedule - i.e. when a flow
version will be executed for a service number. The latest_flow_version_schedule
view is all
the flow scheduling data from the last NiFi extract.
Column Name | Type | Purpose |
---|---|---|
nifi_insert_timestamp | timestamp | The date/time the service data was extracted. |
flow_version_schedule_id | integer | The unique ID of the flow version schedule record. |
service_id | integer | The service number that this schedule record is for. |
flow_version_id | integer | The flow version that is scheduled. |
active_from | integer | The date/time that the linked flow version will start being active for the linked service number. |