メジャーを操作する

このドキュメントでは、グラフで指標を定義してクエリする方法について説明します。メジャーを使用すると、結合全体で集計が正しく実行されるようにできます。

概要

メジャーは、ノードテーブルまたはエッジテーブルの PROPERTIES 句内で定義された集計プロパティです。指標は、MEASURE キーワードと、次のサポートされている集計関数のいずれかを使用して定義されます。

  • SUM
  • AVG
  • COUNT
  • COUNT(DISTINCT)
  • MIN
  • MAX

指標は、定義されているノードテーブルまたはエッジテーブルの KEY を参照して集計を定義します。つまり、基盤となるテーブルが重複する行を生成するような方法で結合されている場合でも、指標をクエリすると集計が正しく実行されます。

GQL クエリで、指標で定義されたプロパティを参照することはできません。代わりに、GRAPH_EXPAND TVF を呼び出してグラフのフラット化されたテーブル表現を作成し、指標にアクセスします。この関数は、すべての種類のグラフを受け入れるわけではありません。有効な入力となるグラフの詳細については、入力の制限事項をご覧ください。GQL クエリを実行するには、Enterprise エディションまたは Enterprise Plus エディションを使用する予約が必要です。オンデマンド料金を使用する場合は、GRAPH_EXPAND 関数を呼び出してグラフで SQL クエリを実行できます。

GRAPH_EXPAND TVF の出力に対して AGG 関数を呼び出して、指標で定義した集計関数に従ってプロパティを集計できます。

メジャーを定義する

ノードまたはエッジテーブル定義の PROPERTIES内で、サポートされている集計関数を MEASURE() キーワードで囲んで、指標を定義します。

次の例では、university という名前のデータセットと、大学、学部、コースのテーブルを作成します。

CREATE SCHEMA IF NOT EXISTS university;

CREATE OR REPLACE TABLE university.College (
  college_id INT64 PRIMARY KEY NOT ENFORCED,
  college_name STRING
);

CREATE OR REPLACE TABLE university.Department (
  dept_id INT64 PRIMARY KEY NOT ENFORCED,
  dept_name STRING,
  college_id INT64,
  budget FLOAT64,
  FOREIGN KEY (college_id) REFERENCES university.College(college_id) NOT ENFORCED
);

CREATE OR REPLACE TABLE university.Course (
  course_id INT64 PRIMARY KEY NOT ENFORCED,
  course_name STRING,
  dept_id INT64,
  credits INT64,
  FOREIGN KEY (dept_id) REFERENCES university.Department(dept_id) NOT ENFORCED
);

INSERT INTO university.College (college_id, college_name)
VALUES (101, 'College of Engineering'),
      (102, 'College of Arts');

INSERT INTO university.Department (dept_id, dept_name, college_id, budget)
VALUES (1001, 'Computer Science', 101, 500000),
      (1002, 'Mechanical Engineering', 101, 400000),
      (1003, 'Fine Arts', 102, 200000),
      (1004, 'Research', 101, 50000);

INSERT INTO university.Course (course_id, course_name, dept_id, credits)
VALUES (1, 'Intro to CS', 1001, 3),
       (2, 'Data Structures', 1001, 4),
       (3, 'Thermodynamics', 1002, 3),
       (4, 'Oil Painting', 1003, 2);

次のステートメントは、Department ノードと Course ノードの一部のプロパティに指標を定義する SchoolGraph というグラフを作成します。指標で定義されたプロパティのエイリアスを指定する必要があります。

CREATE OR REPLACE PROPERTY GRAPH university.SchoolGraph
  NODE TABLES (
    university.College
      KEY(college_id)
      PROPERTIES(college_id, college_name),
    university.Department
      KEY(dept_id)
      PROPERTIES(dept_id, dept_name, college_id,
        budget OPTIONS(description="Department budget in USD"),
        MEASURE(SUM(budget)) AS total_budget),
    university.Course
      KEY(course_id)
      PROPERTIES(
        course_id,
        course_name,
        credits,
        dept_id,
        MEASURE(AVG(credits)) AS avg_credits,
        MEASURE(SUM(credits)) AS total_credits,
        MEASURE(COUNT(course_id)) AS course_count)
  )
  EDGE TABLES (
    university.Department AS CollegeDept
      SOURCE KEY (college_id) REFERENCES College (college_id)
      DESTINATION KEY (dept_id) REFERENCES Department (dept_id),
    university.Course AS DeptCourse
      SOURCE KEY (dept_id) REFERENCES Department (dept_id)
      DESTINATION KEY (course_id) REFERENCES Course (course_id)
  );

SchoolGraph グラフの可視化。

total_budget 指標は MEASURE(SUM(budget)) として定義されます。このメジャーは、集計を KEYdept_id)にロックします。

重複カウントについて

テーブルを結合すると、データに 1 対多の関係があるたびにデータが繰り返されます。たとえば、CourseDepartmentCollege のテーブルを結合すると、複数のコースがある部門が出力の複数の行に表示されます。

SELECT
  college_name,
  dept_name,
  course_name,
  budget
FROM university.Course
LEFT JOIN university.Department
  ON Course.dept_id = Department.dept_id
LEFT JOIN university.College
  ON Department.college_id = College.college_id;

/*------------------------+------------------------+-----------------+----------+
 | college_name           | dept_name              | course_name     | budget   |
 +------------------------+------------------------+-----------------+----------+
 | College of Engineering | Computer Science       | Intro to CS     | 500000.0 |
 | College of Engineering | Computer Science       | Data Structures | 500000.0 |
 | College of Engineering | Mechanical Engineering | Thermodynamics  | 400000.0 |
 | College of Arts        | Fine Arts              | Oil Painting    | 200000.0 |
 +------------------------+------------------------+-----------------+----------*/

SUM(budget) を使用して大学ごとの合計予算を計算しようとすると、コンピュータ サイエンス学部の予算が 2 回カウントされます。この問題を回避するには、Department テーブルを直接クエリしますが、このアプローチは、結合されたデータに寄与する異なるテーブルから複数の集計を計算する場合に機能しません。次のセクションでは、対策によってこの問題が解決される仕組みについて説明します。

measure を使用してグラフをクエリする

GQL を使用して指標を含むグラフをクエリできますが、クエリで指標によって定義されたプロパティを直接参照することはできません。たとえば、次のクエリは、測定プロパティが定義されているノードを参照しますが、測定フィールドを使用したり返したりしません。

GRAPH university.SchoolGraph
MATCH (c:College)-[]-(d:Department)-[]->(course:Course)
RETURN c.college_name, d.dept_name, course.course_name;

/*------------------------+------------------------+-----------------+
 | college_name           | dept_name              | course_name     |
 +------------------------+------------------------+-----------------+
 | College of Engineering | Computer Science       | Intro to CS     |
 | College of Engineering | Computer Science       | Data Structures |
 | College of Engineering | Mechanical Engineering | Thermodynamics  |
 | College of Arts        | Fine Arts              | Oil Painting    |
 +------------------------+------------------------+-----------------*/

メジャーを操作する

メジャーを操作するには、GRAPH_EXPAND テーブル値関数(TVF)を使用して、グラフを単一のフラット化されたテーブルとしてクエリします。出力テーブルの列は、各ノードテーブルとエッジテーブルのグラフで定義されたプロパティから派生します。名前の競合を避けるため、列にはノードまたはエッジのテーブルラベルとプロパティ名を連結した名前が付けられます(例: Course_course_nameDepartment_total_budget)。次のクエリは、GRAPH_EXPAND TVF からの出力例を示しています。

SELECT
  College_college_name,
  Department_dept_name,
  Department_budget,
  Course_course_name
FROM
  GRAPH_EXPAND("university.SchoolGraph");

/*------------------------+------------------------+-------------------+--------------------+
 | College_college_name   | Department_dept_name   | Department_budget | Course_course_name |
 +------------------------+------------------------+-------------------+--------------------+
 | College of Engineering | Computer Science       | 500000.0          | Intro to CS        |
 | College of Engineering | Computer Science       | 500000.0          | Data Structures    |
 | College of Engineering | Mechanical Engineering | 400000.0          | Thermodynamics     |
 | College of Arts        | Fine Arts              | 200000.0          | Oil Painting       |
 +------------------------+------------------------+-------------------+--------------------+

GRAPH_EXPAND 関数は、ノードテーブルとエッジテーブルに一連の LEFT JOIN オペレーションを適用して、フラット化されたテーブルを生成します。有効な入力グラフには、ルートノード テーブルが 1 つだけ必要です。これは、KEY 値が他のテーブルに表示されないテーブルです。一連の結合を通じてルートノード テーブルから到達できないデータは、出力に表示されません。前の例では、Course テーブルがルートノード テーブルです。Research 部門にはコースがないため、出力から除外されています。

メジャーで定義されたプロパティの列を直接選択することはできません。代わりに、AGG() 関数でラップする必要があります。この関数により、指標で定義された集計がキーごとに 1 回だけ実行されます。

次のクエリは、各大学の合計予算と合計コース数を同時に計算します。

SELECT
  College_college_name,
  AGG(Department_total_budget) AS college_budget,
  AGG(Course_course_count) AS total_courses
FROM
  GRAPH_EXPAND("university.SchoolGraph")
GROUP BY
  College_college_name;

/*------------------------+----------------+---------------+
 | College_college_name   | college_budget | total_courses |
 +------------------------+----------------+---------------+
 | College of Engineering | 900000.0       | 3             |
 | College of Arts        | 200000.0       | 1             |
 +------------------------+----------------+---------------*/

ベスト プラクティス

指標を含むグラフを設計する場合は、次のベスト プラクティスに従ってください。

単一テーブル内でノードとエッジを定義する

ノードテーブルの定義とその接続エッジテーブルの定義には、同じテーブルを使用することをおすすめします。テーブルを再利用すると、ノードテーブルとエッジテーブルの間に 1 対 1(1:1)の関係が正確に確保され、ファンアウトが防止されます。また、GRAPH_EXPAND 関数がエッジを曖昧として無視しないようにします。

たとえば、Student テーブルと Course テーブルを指す外部キーを含む入力テーブル Enrollment がある場合は、Enrollment 入力テーブルを使用して Enrollment ノードとその出力エッジを定義します。

多対多の関係をノードテーブルとしてモデル化する

多対多(M:N)リレーションシップは、テーブル A の行がテーブル B の複数の行に対応し、テーブル B の行がテーブル A の複数の行に対応する場合に発生します。たとえば、1 人の生徒が複数のコースに登録でき、1 つのコースに複数の生徒が登録できます。中間結合テーブルを使用すると、多対多の関係を 2 つの 1 対多の関係に分離できます。たとえば、Student テーブルと Course テーブルを指す外部キーを含む Enrollment テーブルを定義できます。CREATE PROPERTY GRAPH ステートメントで 2 つのディメンション ノードテーブルを接続するエッジテーブルとして中間結合テーブルをモデル化すると、GRAPH_EXPAND 関数はこれらのエッジを無視します。これは、これらのエッジの関係が多対一または一対一のいずれでもないためです。

CREATE PROPERTY GRAPH university.SchoolGraph
  NODE TABLES (
    university.Student,
    university.Course
  )
  EDGE TABLES (
    -- Modeling the junction table as a standalone edge causes ambiguity
    university.Enrollment AS StudentEnrollment
      SOURCE KEY (student_id) REFERENCES Student (student_id)
      DESTINATION KEY (course_id) REFERENCES Course (course_id)
  );

これらのエッジは曖昧(ノードテーブル間の多対 1 または 1 対 1 が明確でない)であるため、GRAPH_EXPAND 関数はこれらのエッジを無視します。グラフ内のすべてのエッジが無視される場合、GRAPH_EXPAND または BQ.SHOW_GRAPH_EXPAND_SCHEMA の呼び出しはエラーで失敗します。

指標の M:N 関係を正しくモデル化するには、中間結合テーブルをノードテーブルに昇格させます。この構造では、ジャンクション ノードテーブルは単一のルートノードテーブル(入次数がゼロのノードテーブル)として機能します。次に、結合テーブルを共有して N:1 を各ディメンション ノードテーブルに接続する 2 つの多対一(N:1)エッジテーブルを定義します。

CREATE PROPERTY GRAPH university.SchoolGraph
  NODE TABLES (
    university.Student KEY (student_id),
    university.Course KEY (course_id),
    -- Promote the junction table to a node table (acting as the single root node)
    university.Enrollment KEY (enrollment_id)
  )
  EDGE TABLES (
    -- Share (reuse) the Enrollment table to define N:1 edges to each dimension
    university.Enrollment AS EnrollmentToStudent
      SOURCE KEY (enrollment_id) REFERENCES Enrollment (enrollment_id)
      DESTINATION KEY (student_id) REFERENCES Student (student_id),
    university.Enrollment AS EnrollmentToCourse
      SOURCE KEY (enrollment_id) REFERENCES Enrollment (enrollment_id)
      DESTINATION KEY (course_id) REFERENCES Course (course_id)
  );

この構造では、EnrollmentStudent ディメンション テーブルと Course ディメンション テーブルに N:1 で接続する単一のルートノード テーブル(入次数 0)として機能します。GRAPH_EXPAND 関数は、Enrollment から StudentCourse に外向きにトラバースすることで、このグラフをフラット化できます。これらのテーブルで指標を定義する場合は、指標列で AGG 関数を呼び出して、重複カウントせずに集計を正しく計算できます。

GRAPH_EXPAND スキーマを表示する

関数を呼び出さずに GRAPH_EXPAND 関数から返されるテーブルのスキーマを表示するには、BQ.SHOW_GRAPH_EXPAND_SCHEMA システム プロシージャを使用します。

DECLARE schema STRING DEFAULT '';
CALL BQ.SHOW_GRAPH_EXPAND_SCHEMA('university.SchoolGraph', schema);
SELECT schema;

この手順では、各列の名前、型、モードが schema 変数に設定されます。また、列で参照されるプロパティが指標であるかどうかを示し、定義した説明や同義語を一覧表示します。

次のステップ