Выявление мошенничества с помощью BigQuery Graph

1. Введение

Заголовок маркетинговой статьи - Мошенничество в сфере финансовых технологий

Мошеннические действия часто включают в себя скрытые сети взаимосвязанных объектов — например, несколько учетных записей, использующих один и тот же адрес электронной почты, номер телефона или физический адрес. Традиционные реляционные базы данных с трудом справляются с эффективным запросом к таким сложным, многоступенчатым связям.

BigQuery Graph позволяет анализировать эти сети в больших масштабах, используя графовые базы данных. Вы можете определить граф свойств на основе существующих таблиц BigQuery и использовать язык запросов к графам (GQL) для поиска закономерностей в ваших данных.

Распространенное применение графовых сетей для обнаружения мошенничества — это блокировка заказов, адрес доставки которых связан с мошеннической сетью, или блокировка платежей, принадлежащих .

В этом практическом занятии вы создадите решение для обнаружения мошенничества с использованием BigQuery Graph. Вы загрузите данные из Cloud Storage, создадите граф свойств и используете запросы к графу для выявления подозрительных соединений.

Что вы узнаете

  • Как создать набор данных BigQuery и загрузить данные.
  • Как определить граф свойств с помощью DDL.
  • Как выполнить запрос к графу с помощью GQL.
  • Как использовать графовую аналитику для выявления мошенничества.

Что вам понадобится

  • Проект Google Cloud с включенной функцией выставления счетов.
  • Среда разработки блокнотов BigQuery (BigQuery Studio или Colab Enterprise).

Расходы

В этой лабораторной работе используются платные ресурсы Google Cloud. Ориентировочная стоимость составляет менее 5 долларов США при условии удаления ресурсов после завершения работы.

2. Прежде чем начать

Выберите или создайте проект Google Cloud.

  1. В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud.
  2. Убедитесь, что для вашего проекта Google Cloud включена оплата. Узнайте, как проверить, включена ли оплата .

Выберите свою среду

Для выполнения этой лабораторной работы вам потребуется среда для работы с ноутбуками. Вы можете использовать BigQuery Studio или Colab Enterprise .

  1. Перейдите на страницу BigQuery в консоли Google Cloud.
  2. Для выполнения запросов к графу вы будете использовать блокнот Python.

Запустить Cloud Shell

  1. В верхней части консоли Google Cloud нажмите кнопку «Активировать Cloud Shell» .
  2. Подтвердите подлинность:
gcloud auth list
  1. Подтвердите свой проект:
gcloud config get project
  1. При необходимости установите значение:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID

Включить API

Выполните эту команду, чтобы включить необходимый API BigQuery:

gcloud services enable bigquery.googleapis.com

3. Загрузка данных

На этом этапе вы создадите набор данных BigQuery и загрузите примеры данных из облачного хранилища.

Пример данных состоит из нескольких CSV-файлов, представляющих собой смоделированную среду розничной торговли:

  • customers.csv : Информация об учетной записи клиента.
  • emails.csv : Адреса электронной почты.
  • phones.csv : Номера телефонов.
  • addresses.csv : Физические адреса.
  • customer_emails.csv , customer_phones.csv , customer_addresses.csv : Связывание таблиц.
  • orders.csv : История заказов, включая сообщения о мошенничестве.

Создайте набор данных

Создайте набор данных с именем fraud_demo для хранения таблиц.

  1. В этом практическом занятии мы будем выполнять команды SQL. Вы можете запустить эти команды в BigQuery Studio > SQL Editor или использовать команду bq query в Cloud Shell. Новый SQL-запрос Для удобства работы с многострочными операторами создания запросов мы будем исходить из того, что вы используете редактор SQL BigQuery .
CREATE SCHEMA IF NOT EXISTS `fraud_demo` OPTIONS(location="US");

Таблицы загрузки

Выполните следующие SQL-запросы, чтобы загрузить данные из облачного хранилища в ваш набор данных.

LOAD DATA OVERWRITE `fraud_demo.customers`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customers.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.emails`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/emails.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.phones`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/phones.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.addresses`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/addresses.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.customer_emails`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customer_emails.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.customer_phones`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customer_phones.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.customer_addresses`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/customer_addresses.csv'],
  skip_leading_rows = 1
);

LOAD DATA OVERWRITE `fraud_demo.orders`
FROM FILES (
  format = 'CSV',
  uris = ['gs://sample-data-and-media/fraud-demo-data/orders.csv'],
  skip_leading_rows = 1
);

4. Создайте граф свойств.

Теперь, когда данные загружены, вы можете определить граф свойств. Граф свойств состоит из узлов (сущностей) и ребер (связей).

В этой лабораторной работе используются следующие узлы:

  • Клиент : Представляет интересы владельца счета.
  • Телефон : обозначает номер телефона.
  • Email : Обозначает адрес электронной почты.
  • Адрес : обозначает физический адрес.

Края:

  • OwnsPhone : Подключает клиента к телефону.
  • OwnsEmail : Подключает клиента к адресу электронной почты.
  • LinkedToAddress : Связывает клиента с адресом.

Создайте график

Выполните следующую инструкцию DDL, чтобы создать граф с именем FraudDemo в вашем наборе данных fraud_demo .

CREATE OR REPLACE PROPERTY GRAPH fraud_demo.FraudDemo
  NODE TABLES(
    fraud_demo.customers
      KEY(account_id)
      LABEL Customer PROPERTIES(
        account_id,
        name),

    fraud_demo.emails
      KEY(email)
      LABEL Email PROPERTIES(
        email,
        email_type),

    fraud_demo.phones
      KEY(phone_number)
      LABEL Phone PROPERTIES(
        phone_number,
        phone_type),

    fraud_demo.addresses
      KEY(address)
      LABEL Address PROPERTIES(
        address,
        address_type)
  )
  EDGE TABLES(
    fraud_demo.customer_emails
      KEY(account_id, email)
      SOURCE KEY(account_id) REFERENCES customers(account_id)
      DESTINATION KEY(email) REFERENCES emails(email)
      LABEL OwnsEmail PROPERTIES(
        account_id,
        email,
        last_updated_ts),

    fraud_demo.customer_phones
      KEY(account_id, phone_number)
      SOURCE KEY(account_id) REFERENCES customers(account_id)
      DESTINATION KEY(phone_number) REFERENCES phones(phone_number)
      LABEL OwnsPhone PROPERTIES(
        account_id,
        phone_number,
        last_updated_ts),

    fraud_demo.customer_addresses
      KEY(account_id, address)
      SOURCE KEY(account_id) REFERENCES customers(account_id)
      DESTINATION KEY(address) REFERENCES addresses(address)
      LABEL LinkedToAddress PROPERTIES(
        account_id,
        address,
        last_updated_ts)
  );

5. Анализ сетей (двухскачковые)

Откройте новую записную книжку в BigQuery Studio.

Создать новую записную книжку

Для визуализации и рекомендательных частей этого практического занятия мы будем использовать блокнот Google Colab в BigQuery Studio. Это позволит нам легко визуализировать результаты построения графа.

Блокнот BigQuery Graph Notebook реализован как магическая команда IPython. Добавив магическую команду %%bigquery с функцией TO_JSON , вы можете визуализировать результаты, как показано в следующих разделах. На этом шаге вы выполните запрос к графу для поиска простых связей между учетными записями. Это запрос с двумя переходами, поскольку он проходит два перехода от начального узла, чтобы найти связанные узлы (например, Клиент -> Электронная почта -> Клиент).

Начнём с проверки аккаунта, принадлежащего Николь Уэйд . Мы хотим найти все связанные с ней аккаунты, используя два шага поиска.

Выполните запрос с двумя переходами.

Выполните следующий запрос в своем блокноте.

%%bigquery --graph
GRAPH fraud_demo.FraudDemo
MATCH 
 p=(a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress WHERE e.last_updated_ts < '2025-07-30']- (n) ){2}
WHERE a.account_id IN ("d2f1f992-d116-41b3-955b-6c76a3352657")
  -- Verify the final node in the hop array is a Customer
  AND 'Customer' IN UNNEST(LABELS(n[OFFSET(1)]))

RETURN TO_JSON(p) AS paths

Разберитесь в результатах.

Этот запрос:

  1. Начинается с узла Customer с account_id "d2f1f992-d116-41b3-955b-6c76a3352657" (Николь Уэйд).
  2. Следует по любому из ребер OwnsEmail , OwnsPhone или LinkedToAddress к соединяющему узлу ( Phone , Email или Address ).
  3. Прослеживает ребра от этого соединительного узла к другим узлам Customer .
  4. Фильтрует ребра на основе временной метки ( last_updated_ts ), чтобы увидеть состояние сети в определенный момент времени.

Вы должны заметить, что Закари Кордова и Бренда Браун связаны с Николь по одному и тому же адресу.

6. Анализ сетей (4-скачковые)

На этом этапе вы расширите запрос, чтобы найти более сложные взаимосвязи. Мы будем искать соединения с четырьмя переходами . Это позволит нам найти учетные записи, связанные через несколько промежуточных сущностей (например, Клиент A -> Электронная почта -> Клиент B -> Телефон -> Клиент C).

Мы также понаблюдаем за тем, как эта сеть меняется с течением времени.

Состояние «до»

Для начала давайте посмотрим на сеть в том виде, в котором она существовала 30 июля 2025 года .

Выполните следующий запрос:

%%bigquery --graph
%%bigquery --graph

MATCH p= ANY SHORTEST (a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress WHERE e.last_updated_ts < '2025-07-30']- (n) ){3, 5}(reachable_a:Customer)
WHERE a.account_id IN ("d2f1f992-d116-41b3-955b-6c76a3352657")
  -- Ensure the final node in the dynamic chain is actually a Customer
  AND 'Customer' IN UNNEST(LABELS(n[OFFSET(ARRAY_LENGTH(n) - 1)]))
GRAPH fraud_demo.FraudDemo
RETURN 
  TO_JSON(p) AS paths,                   -- Array of all traversed edges
  ARRAY_LENGTH(e) AS hop_count

Пост-состояние

Теперь давайте посмотрим, как будет выглядеть сеть через 2 недели . Мы выполним тот же запрос, но без ограничений по дате.

Выполните следующий запрос:

%%bigquery --graph
GRAPH fraud_demo.FraudDemo
MATCH p= ANY SHORTEST (a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress]- (n) ){3, 5}(reachable_a:Customer)
WHERE a.account_id IN ("d2f1f992-d116-41b3-955b-6c76a3352657")
  -- Ensure the final node in the dynamic chain is actually a Customer
  AND 'Customer' IN UNNEST(LABELS(n[OFFSET(ARRAY_LENGTH(n) - 1)]))

RETURN 
  TO_JSON(p) AS paths,                   -- Array of all traversed edges
  ARRAY_LENGTH(e) AS hop_count

Разберитесь в результатах.

Убрав фильтры по дате, вы получаете запрос ко всему набору данных. Вы заметите, что сеть значительно расширилась. Николь Уэйд теперь является частью гораздо более крупной, тесно связанной группы. Такое быстрое расширение связанной сети является сильным индикатором потенциально мошеннической деятельности, например, когда мошенническая группа делит ресурсы в течение определенного времени.

7. Составьте отчет о мошенничестве.

На этом этапе вы объедините графовую аналитику с традиционными бизнес-данными (заказами), чтобы создать всеобъемлющий отчет о мошенничестве. Вы выявите учетные записи, находящиеся под угрозой, и потенциально мошеннические заказы.

Этот запрос более сложный. Он использует GRAPH_TABLE для выполнения запроса к графу внутри стандартного SQL и вычисляет изменение размера сети ( diff ) между состояниями «до» и «после», которые мы наблюдали на предыдущем шаге.

Выполните запрос по отчету о мошенничестве.

Выполните следующий запрос в своем блокноте.

%%bigquery --graph
WITH num_orders AS (
  SELECT account_id, COUNT(1) AS num_order
  FROM fraud_demo.orders
  WHERE order_time > '2025-07-30'
  GROUP BY account_id
),

orders AS (
  SELECT account_id, order_id, fraud, order_total
  FROM fraud_demo.orders
  WHERE order_time > '2025-07-30'
),

-- Use Quantified Path Patterns to find connections up to 4 hops away
latest_connect AS (
  SELECT 
    account_id, 
    ARRAY_LENGTH(ARRAY_AGG(DISTINCT connected_id)) AS size
  FROM GRAPH_TABLE(
    fraud_demo.FraudDemo
    MATCH (a:Customer)-[:OwnsEmail|OwnsPhone|LinkedToAddress]-{4}(connected:Customer)
    RETURN a.account_id AS account_id, connected.account_id AS connected_id
  )
  GROUP BY account_id
),

prev_connect AS (
  SELECT 
    account_id, 
    ARRAY_LENGTH(ARRAY_AGG(DISTINCT connected_id)) AS size
  FROM GRAPH_TABLE(
    fraud_demo.FraudDemo
    -- Apply the timestamp filter to EVERY edge in the 4-hop chain
    MATCH (a:Customer)
          (-[e:OwnsEmail|OwnsPhone|LinkedToAddress WHERE e.last_updated_ts < '2025-07-30']-(n)){4}
    WHERE 'Customer' IN UNNEST(LABELS(n[OFFSET(3)]))
    RETURN a.account_id AS account_id, n[OFFSET(3)].account_id AS connected_id
  )
  GROUP BY account_id
),

edge_changes AS (
  SELECT account_id, MAX(last_updated_ts) AS max_last_updated_ts
  FROM fraud_demo.customer_addresses
  GROUP BY account_id
)

SELECT
    la.account_id,
    o.order_id,
    la.size AS latest_size,
    COALESCE(pa.size, 0) AS previous_size,
    la.size - COALESCE(pa.size, 0) AS diff,
    nos.num_order,
    o.fraud AS reported_as_fraud,
    o.order_total,

    CASE
      WHEN (la.size - COALESCE(pa.size, 0)) > 10 AND nos.num_order IS NULL THEN "CUSTOMER AT RISK"
      WHEN (la.size - COALESCE(pa.size, 0)) > 10 AND nos.num_order IS NOT NULL AND o.fraud THEN "CONFIRMED FRAUD ORDER"
      WHEN (la.size - COALESCE(pa.size, 0)) > 10 AND nos.num_order IS NOT NULL AND NOT o.fraud THEN "POTENTIAL FRAUD ORDER"
      ELSE ""
    END AS notes
FROM latest_connect la
LEFT JOIN prev_connect pa ON la.account_id = pa.account_id
LEFT JOIN num_orders nos ON la.account_id = nos.account_id
LEFT JOIN orders o ON la.account_id = o.account_id
INNER JOIN edge_changes ec ON la.account_id = ec.account_id
WHERE nos.num_order > 1 OR (la.size - COALESCE(pa.size, 0)) > 10
ORDER BY diff DESC

Разберитесь в результатах.

В этом отчете показано:

  • account_id : Идентификатор анализируемой учетной записи.
  • order_id : Идентификатор последнего заказа.
  • latest_size : Размер подключенной сети на сегодняшний день.
  • previous_size : Размер сети 2 недели назад.
  • diff : Рост размера сети.
  • num_order : Количество последних заказов.
  • reported_as_fraud : Указано, был ли заказ помечен как мошеннический.
  • order_total : Общая сумма заказа.
  • notes : Расчетный уровень риска, основанный на росте сети и истории заказов.

Вы увидите счета с большими diff значениями и высокими суммами заказов, которые являются основными кандидатами на дальнейшее расследование. Примечания «КЛИЕНТ В РИСКЕ» и «ПОТЕНЦИАЛЬНЫЙ МОШЕННИЧЕСКИЙ ЗАКАЗ» помогут определить приоритетность таких счетов.

8. Выявление в масштабе

На заключительном этапе анализа вы визуализируете сеть в более крупном масштабе. Вместо того чтобы начинать с одной учетной записи, вы будете запрашивать связи между набором подозрительных учетных записей.

Это помогает определить, являются ли несколько независимых расследований частью одной и той же крупной мошеннической схемы.

Выполните масштабированный запрос

Выполните следующий запрос в своем блокноте.

%%bigquery --graph
GRAPH fraud_demo.FraudDemo
MATCH
p= ANY SHORTEST (a:Customer) 
  ( -[e:OwnsEmail|OwnsPhone|LinkedToAddress]- (n) ){3, 5}
(reachable_a:Customer)
-- these IDs are from the previous results
WHERE a.account_id in (   "845f2b14-cd10-4750-9f28-fe542c4a731b"
  , "3ff59684-fbf9-40d7-8c41-285ade5002e6"
  , "8887c17b-e6fb-4b3b-8c62-cb721aafd028"
  , "03e777e5-6fb4-445d-b48c-cf42b7620874"
  , "81629832-eb1d-4a0e-86da-81a198604898"
  , "845f2b14-cd10-4750-9f28-fe542c4a731b",
   "89e9a8fe-ffc4-44eb-8693-a711a3534849"
 )
 LIMIT 400
RETURN TO_JSON(p) as paths

Разберитесь в результатах.

Этот запрос возвращает сложный граф, показывающий, как указанные подозрительные учетные записи пересекаются и совместно используют ресурсы. Теперь вы занимаетесь обнаружением мошенничества в масштабе предприятия, выявляя кластеры активности, которые могут потребовать скоординированных действий.

9. Уборка

Чтобы избежать списания средств с вашего аккаунта Google Cloud за ресурсы, использованные в этом практическом задании, вам следует удалить набор данных и граф свойств.

Выполните следующие SQL-запросы для очистки вашей среды.

DROP PROPERTY GRAPH IF EXISTS fraud_demo.FraudDemo;
DROP SCHEMA IF EXISTS fraud_demo CASCADE;

10. Поздравляем!

Поздравляем! Вы успешно разработали решение для обнаружения мошенничества с использованием BigQuery Graph.

Вы научились:

  • Загрузка данных из облачного хранилища в BigQuery.
  • Определите граф свойств с помощью DDL.
  • С помощью GQL выполните запрос к графу, чтобы найти простые и сложные взаимосвязи.
  • Сочетайте анализ графов с бизнес-данными для выявления рисков.
  • Визуализация сетей в масштабе.

Дополнительные ресурсы