← Back to Stack Overflow Dataset

TigerGraph Implementation

Deployment and Query logic for TigerGraph Community 4.2.0.

Schema Diagram and Graph Statistics

StackOverflow TigerGraph Schema

Total node count: 445,272,721

Total edge count: 782,719,894

Data Loading

Overview

We mainly used the TigerGraph browser GSQLShell to import the data. You should map your local directory where your raw data files are stored to the TigerGraph dataset directory /home/tigergraph/datasets/. For how to do this, check our documentation page.

Creating Graph Schema

Use the GSQLShell tool on the TigerGraph to create vertex and edge types.

gsql
USE GLOBAL
CREATE GRAPH StackOverflow()

Define Vertices

Then we define User, Badge, Comment, Post_question, Post_answer, Tag, Vote, Post_tag_wiki, and Post_tag_wiki_excerpt vertices.

gsql
CREATE VERTEX User (
    PRIMARY_ID id STRING,
    display_name STRING,
    about_me STRING,
    age INT,
    creation_date DATETIME,
    last_access_date DATETIME,
    location STRING,
    reputation INT,
    up_votes INT,
    down_votes INT,
    views INT,
    profile_image_url STRING,
    website_url STRING
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Badge (
    PRIMARY_ID id STRING,
    name STRING,
    date DATETIME,
    user_id INT,
    class STRING,
    tag_based STRING
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Comment (
    PRIMARY_ID id STRING,
    text STRING,
    creation_date DATETIME,
    post_id INT,
    user_id INT,
    user_display_name STRING,
score INT
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Post_question (
    PRIMARY_ID id STRING,
    accepted_answer_id INT,
    answer_count INT,
    comment_count INT,
    community_owned_date DATETIME,
    creation_date DATETIME,
    favorite_count INT,
    last_activity_date DATETIME,
    last_edit_date DATETIME,
    last_editor_display_name STRING,
    last_editor_user_id INT,
    owner_display_name STRING,
    owner_user_id INT,
    parent_id INT,
    post_type_id INT,
    score INT,
    tags STRING,
    view_count INT
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Post_answer (
    PRIMARY_ID id STRING,
    title STRING,
    body STRING,
    accepted_answer_id INT,
    answer_count INT,
    comment_count INT,
    community_owned_date DATETIME,
    creation_date DATETIME,
    favorite_count INT,
    last_activity_date DATETIME,
    last_edit_date DATETIME,
    last_editor_display_name STRING,
    last_editor_user_id INT,
    owner_display_name STRING,
    owner_user_id INT,
    parent_id INT,
    post_type_id INT,
    score INT,
    tags STRING,
    view_count INT
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Tag (
    PRIMARY_ID id STRING,
    tag_name STRING,
    tag_count INT,
    excerpt_post_id INT,
    wiki_post_id INT
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Vote (
    PRIMARY_ID id STRING,
    creation_date DATETIME,
    post_id INT,
    vote_type_id INT
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Post_tag_wiki (
    PRIMARY_ID id STRING,
    title STRING,
    body STRING,
    accepted_answer_id INT,
    answer_count INT,
    comment_count INT,
    community_owned_date DATETIME,
    creation_date DATETIME,
    favorite_count INT,
    last_activity_date DATETIME,
    last_edit_date DATETIME,
    last_editor_display_name STRING,
    last_editor_user_id INT,
    owner_display_name STRING,
    owner_user_id INT,
    parent_id INT,
    post_type_id INT,
    score INT,
    post_tag_wiki_tags STRING,
    view_count INT
) WITH primary_id_as_attribute="true"
gsql
CREATE VERTEX Post_tag_wiki_excerpt (
    PRIMARY_ID id STRING,
    title STRING,
    body STRING,
    accepted_answer_id STRING,
    answer_count INT,
    comment_count INT,
    community_owned_date DATETIME,
    creation_date DATETIME,
    favorite_count INT,
    last_activity_date DATETIME,
    last_edit_date DATETIME,
    last_editor_display_name STRING,
    last_editor_user_id INT,
    owner_display_name STRING,
    owner_user_id INT,
    parent_id STRING,
    post_type_id INT,
    score INT,
    post_tag_wiki_excerpt_tags STRING,
    view_count INT
) WITH primary_id_as_attribute="true"

Define Edges

Next we define 21 edge types. The meanings and the connected node labels should be pretty straightforward from the definition language.

gsql
CREATE UNDIRECTED EDGE Owned_by (FROM Post_question, TO User)
CREATE UNDIRECTED EDGE Answers_by (FROM Post_answer, TO User)
CREATE UNDIRECTED EDGE Created_by_wiki (FROM Post_tag_wiki, TO User)
CREATE UNDIRECTED EDGE Created_by_excerpt (FROM Post_tag_wiki_excerpt, TO User)
CREATE UNDIRECTED EDGE Last_edited_by_question (FROM Post_question, TO User)
CREATE UNDIRECTED EDGE Last_edited_by_answer (FROM Post_answer, TO User)
CREATE UNDIRECTED EDGE Last_edited_by_wiki (FROM Post_tag_wiki, TO User)
CREATE UNDIRECTED EDGE Last_edited_by_excerpt (FROM Post_tag_wiki_excerpt, TO User)
CREATE UNDIRECTED EDGE Earns (FROM User, TO Badge)
CREATE UNDIRECTED EDGE Answers_to (FROM Post_answer, TO Post_question)
CREATE UNDIRECTED EDGE Accepts (FROM Post_question, TO Post_answer)
CREATE UNDIRECTED EDGE Commented_by (FROM Comment, TO User)
CREATE UNDIRECTED EDGE On_question (FROM Comment, TO Post_question)
CREATE UNDIRECTED EDGE On_answer (FROM Comment, TO Post_answer)
CREATE UNDIRECTED EDGE Vote_on_question (FROM Vote, TO Post_question)
CREATE UNDIRECTED EDGE Vote_on_answer (FROM Vote, TO Post_answer)
CREATE UNDIRECTED EDGE Vote_on_comment (FROM Vote, TO Comment)
CREATE UNDIRECTED EDGE Tag_to (FROM Tag, TO Post_question)
CREATE UNDIRECTED EDGE Has_wiki (FROM Tag, TO Post_tag_wiki)
CREATE UNDIRECTED EDGE Has_wiki_excerpt (FROM Tag, TO Post_tag_wiki_excerpt)
CREATE UNDIRECTED EDGE Link_to (FROM Post_question, TO Post_question)

Create Import Job to Import Data for Nodes and Edges

First make sure we are using the correct graph schema StackOverflow.

gsql
USE GRAPH StackOverflow
gsql
CREATE LOADING JOB load_users FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/users_clean.csv";
    LOAD f
        TO VERTEX User VALUES (
            $"id",
            $"display_name",
            $"about_me",
            $"age",
            $"creation_date",
            $"last_access_date",
            $"location",
            $"reputation",
            $"up_votes",
            $"down_votes",
            $"views",
            $"profile_image_url",
            $"website_url"
        )
        USING SEPARATOR=",", HEADER="true", QUOTE="double";
}

RUN LOADING JOB load_users
gsql
CREATE LOADING JOB load_badges FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/badges.csv";
    LOAD f
        TO VERTEX Badge VALUES (
            $"id",
            $"name",
            $"date",
            $"user_id",
            $"class",
            $"tag_based"
        )
        USING SEPARATOR=",", HEADER="true", EOL="\n", QUOTE="double";
}

RUN LOADING JOB load_badges
gsql
CREATE LOADING JOB load_comment FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/comments_final.csv";
    LOAD f
        TO VERTEX Comment VALUES (
            $"id",
            $"text",
            $"creation_date",
            $"post_id",
            $"user_id",
            $"user_display_name",
            $"score"
        )
        USING SEPARATOR=",", HEADER="true", QUOTE="double";
}

RUN LOADING JOB load_comment
gsql
CREATE LOADING JOB load_post_question FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_questions_cleaned1.csv";
    LOAD f
        TO VERTEX Post_question VALUES (
            $"id",
            $"accepted_answer_id",
            $"answer_count",
            $"comment_count",
            $"community_owned_date",
            $"creation_date",
            $"favorite_count",
            $"last_activity_date",
            $"last_edit_date",
            $"last_editor_display_name",
            $"last_editor_user_id",
            $"owner_display_name",
            $"owner_user_id",
            $"parent_id",
            $"post_type_id",
            $"score",
            $"tags",
            $"view_count"
        )
        USING SEPARATOR=",", HEADER="true", QUOTE="double";
}

RUN LOADING JOB load_post_question
gsql
CREATE LOADING JOB load_post_answer FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_answers_fixed.csv";
    LOAD f
        TO VERTEX Post_answer VALUES (
            $"id",
            $"title",
            $"body",
            $"accepted_answer_id",
            $"answer_count",
            $"comment_count",
            $"community_owned_date",
            $"creation_date",
            $"favorite_count",
            $"last_activity_date",
            $"last_edit_date",
            $"last_editor_display_name",
            $"last_editor_user_id",
            $"owner_display_name",
            $"owner_user_id",
            $"parent_id",
            $"post_type_id",
            $"score",
            $"tags",
            $"view_count"
        )
        USING SEPARATOR=",", HEADER="true", QUOTE="double";
}

RUN LOADING JOB load_post_answer
gsql
CREATE LOADING JOB load_tags FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/tags.csv";
    LOAD f
        TO VERTEX Tag VALUES (
            $"id",
            $"tag_name",
            $"count",
            $"excerpt_post_id",
            $"wiki_post_id"
        )
        USING SEPARATOR=",", HEADER="true";
}

RUN LOADING JOB load_tags
gsql
CREATE LOADING JOB load_vote FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/votes.csv";
    LOAD f
        TO VERTEX Vote VALUES (
            $"id",
            $"creation_date",
            $"post_id",
            $"vote_type_id"
        )
        USING SEPARATOR=",", HEADER="true";
}

RUN LOADING JOB load_vote
gsql
CREATE LOADING JOB load_posts_tag_wiki FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_tag_wiki_clean.csv";
    LOAD f
        TO VERTEX Post_tag_wiki VALUES (
            $"id",
            $"title",
            $"body",
            $"accepted_answer_id",
            $"answer_count",
            $"comment_count",
            $"community_owned_date",
            $"creation_date",
            $"favorite_count",
            $"last_activity_date",
            $"last_edit_date",
            $"last_editor_display_name",
            $"last_editor_user_id",
            $"owner_display_name",
            $"owner_user_id",
            $"parent_id",
            $"post_type_id",
            $"score",
            $"tags",
            $"view_count"
        )
        USING SEPARATOR=",", HEADER="true", QUOTE="double";
}

RUN LOADING JOB load_posts_tag_wiki
gsql
CREATE LOADING JOB load_posts_tag_wiki_excerpt FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_tag_wiki_excerpt_100PCT.csv";
    LOAD f
        TO VERTEX Post_tag_wiki_excerpt VALUES (
            $"id",
            $"title",
            $"body",
            $"accepted_answer_id",
            $"answer_count",
            $"comment_count",
            $"community_owned_date",
            $"creation_date",
            $"favorite_count",
            $"last_activity_date",
            $"last_edit_date",
            $"last_editor_display_name",
            $"last_editor_user_id",
            $"owner_display_name",
            $"owner_user_id",
            $"parent_id",
            $"post_type_id",
            $"score",
            $"tags",
            $"view_count"
        )
        USING SEPARATOR=",", HEADER="true", QUOTE="double";
}

RUN LOADING JOB load_posts_tag_wiki_excerpt
gsql
CREATE LOADING JOB load_owned_by FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_questions_cleaned1.csv";
    LOAD f TO EDGE Owned_by VALUES (
        $"id",
        $"owner_user_id"
    ) WHERE $"owner_user_id" != "" AND $"owner_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_owned_by
gsql
CREATE LOADING JOB load_answers_by FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_answers_fixed.csv";
    LOAD f TO EDGE Answers_by VALUES ($"id", $"owner_user_id")
    WHERE $"owner_user_id" != "" AND $"owner_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_answers_by
gsql
CREATE LOADING JOB load_last_edited_by_question FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_questions_cleaned1.csv";
    LOAD f TO EDGE Last_edited_by_question VALUES ($"id", $"last_editor_user_id")
    WHERE $"last_editor_user_id" != "" AND $"last_editor_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_last_edited_by_question
gsql
CREATE LOADING JOB load_last_edited_by_answer FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_answers_fixed.csv";
    LOAD f TO EDGE Last_edited_by_answer VALUES ($"id", $"last_editor_user_id")
    WHERE $"last_editor_user_id" != "" AND $"last_editor_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_last_edited_by_answer
gsql
CREATE LOADING JOB load_created_by_wiki FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_tag_wiki_clean.csv";
    LOAD f TO EDGE Created_by_wiki VALUES ($"id", $"owner_user_id")
    WHERE $"owner_user_id" != "" AND $"owner_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_created_by_wiki
gsql
CREATE LOADING JOB load_created_by_excerpt FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_tag_wiki_excerpt_100PCT.csv";
    LOAD f TO EDGE Created_by_excerpt VALUES ($"id", $"owner_user_id")
    WHERE $"owner_user_id" != "" AND $"owner_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_created_by_excerpt
gsql
CREATE LOADING JOB load_last_edited_by_wiki FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_tag_wiki_clean.csv";
    LOAD f TO EDGE Last_edited_by_wiki VALUES ($"id", $"last_editor_user_id")
    WHERE $"last_editor_user_id" != "" AND $"last_editor_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_last_edited_by_wiki
gsql
CREATE LOADING JOB load_last_edited_by_excerpt FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_tag_wiki_excerpt_100PCT.csv";
    LOAD f TO EDGE Last_edited_by_excerpt VALUES ($"id", $"last_editor_user_id")
    WHERE $"last_editor_user_id" != "" AND $"last_editor_user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_last_edited_by_excerpt
gsql
CREATE LOADING JOB load_earns FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/badges.csv";
    LOAD f TO EDGE Earns VALUES ($"user_id", $"id")
    WHERE $"user_id" != "" AND $"user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_earns
gsql
CREATE LOADING JOB load_answers_to FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_answers_fixed.csv";
    LOAD f TO EDGE Answers_to VALUES ($"id", $"parent_id")
    WHERE $"parent_id" != "" AND $"parent_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_answers_to
gsql
CREATE LOADING JOB load_accepts FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_questions_cleaned1.csv";
    LOAD f TO EDGE Accepts VALUES ($"id", $"accepted_answer_id")
    WHERE $"accepted_answer_id" != "" AND $"accepted_answer_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_accepts
gsql
CREATE LOADING JOB load_commented_by FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/comments_final.csv";
    LOAD f TO EDGE Commented_by VALUES ($"id", $"user_id")
    WHERE $"user_id" != "" AND $"user_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_commented_by
gsql
CREATE LOADING JOB load_on_question FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/comments_final.csv";
    LOAD f TO EDGE On_question VALUES ($"id", $"post_id")
    WHERE $"post_id" != "" AND $"post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_on_question
gsql
CREATE LOADING JOB load_on_answer FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/comments_final.csv";
    LOAD f TO EDGE On_answer VALUES ($"id", $"post_id")
    WHERE $"post_id" != "" AND $"post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_on_answer
gsql
CREATE LOADING JOB load_vote_on_question FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/votes.csv";
    LOAD f TO EDGE Vote_on_question VALUES ($"id", $"post_id")
    WHERE $"post_id" != "" AND $"post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_vote_on_question
gsql
CREATE LOADING JOB load_vote_on_answer FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/votes.csv";
    LOAD f TO EDGE Vote_on_answer VALUES ($"id", $"post_id")
    WHERE $"post_id" != "" AND $"post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_vote_on_answer
gsql
CREATE LOADING JOB load_vote_on_comment FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/votes.csv";
    LOAD f TO EDGE Vote_on_comment VALUES ($"id", $"post_id")
    WHERE $"post_id" != "" AND $"post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_vote_on_comment
gsql
CREATE LOADING JOB load_tag_to FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/edge_tag_to_question.csv";
    LOAD f TO EDGE Tag_to VALUES ($"src", $"dst")
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_tag_to
gsql
CREATE LOADING JOB load_has_wiki FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/tags.csv";
    LOAD f TO EDGE Has_wiki VALUES ($"id", $"wiki_post_id")
    WHERE $"wiki_post_id" != "" AND $"wiki_post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_has_wiki
gsql
CREATE LOADING JOB load_has_wiki_excerpt FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/tags.csv";
    LOAD f TO EDGE Has_wiki_excerpt VALUES ($"id", $"excerpt_post_id")
    WHERE $"excerpt_post_id" != "" AND $"excerpt_post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_has_wiki_excerpt
gsql
CREATE LOADING JOB load_link_to FOR GRAPH StackOverflow {
    DEFINE FILENAME f = "/home/tigergraph/datasets/stackoverflow/posts_links.csv";
    LOAD f TO EDGE Link_to VALUES ($"post_id", $"related_post_id")
    WHERE $"post_id" != "" AND $"related_post_id" != "" AND $"post_id" != "0" AND $"related_post_id" != "0"
    USING SEPARATOR=",", HEADER="true", QUOTE="double", VERTEX_MUST_EXIST="true";
}
RUN LOADING JOB load_link_to

We modified some of the CSV files from the original table pulled from Google Big Query. To find out what we did, please go to the Download page and find our document for Stack Overflow on TigerGraph.

Queries

Select a query below to view its logic and description.

1. Neighborhood
No queries in this category.
2. Path
3. Pattern
4. Aggregation
5. Analytics
6. Others

Q1. User Pairs with Most Question-Answer Interactions

Subcategory: T3.5 Two-hop Join Pattern

This query finds answerer-questioner pairs connected through answer posts and question posts, counts how many times one user answered another user's questions, and returns pairs with at least five such interactions.

gsql
CREATE OR REPLACE DISTRIBUTED QUERY Query1(INT min_interactions = 5) FOR GRAPH StackOverflow {
    MapAccum<STRING, SumAccum<INT>> @@answerer_questioner_pairs;
    all_answers = {Post_answer.*};
    questions_answered = SELECT q
                    FROM all_answers:a -(Answers_to)- Post_question:q
                    WHERE a.owner_user_id != 0 AND q.owner_user_id != 0
                    ACCUM 
                        STRING pair_key = to_string(a.owner_user_id) + ":" + to_string(q.owner_user_id),
                        @@answerer_questioner_pairs += (pair_key -> 1);
    FOREACH (pair_key, interaction_count) IN @@answerer_questioner_pairs DO
        IF interaction_count >= min_interactions THEN
            PRINT pair_key, interaction_count;
        END;
    END;
}

Equivalent query in GQL standard:

gql
MATCH (a:Post_answer)-[:Answers_to]->(q:Post_question)
MATCH (a)-[:Answers_by]->(answerer:User)
MATCH (q)-[:Owned_by]->(questioner:User)
WHERE answerer.id <> questioner.id
WITH (answerer.id + ':' + questioner.id) AS pair_key,
    count(*) AS interaction_count
WHERE interaction_count >= 5
RETURN pair_key, interaction_count
ORDER BY interaction_count DESC
LIMIT 100;

Q2. Tags with Highest Question-to-Answer Ratio

Subcategory: T4.2 Grouped Node Degree Statistics by Label

This query groups questions by tag, counts both tagged questions and answers attached to those questions, then ranks tags by the highest question-to-answer ratio.

gsql
CREATE DISTRIBUTED QUERY Query2(INT limit_count = 200) FOR GRAPH StackOverflow {
    TYPEDEF TUPLE<STRING tag_name, INT question_count, INT answer_count, DOUBLE ratio> TagStats;
    HeapAccum<TagStats>(limit_count, ratio DESC) @@top_tags;
    MapAccum<STRING, SumAccum<INT>> @@tag_question_count, @@tag_answer_count;
    all_tags = {Tag.*};
    questions_by_tag = SELECT q FROM all_tags:t -(Tag_to)- Post_question:q
                  ACCUM @@tag_question_count += (t.tag_name -> 1);
    answers_by_tag = SELECT a FROM all_tags:t -(Tag_to)- Post_question:q -(Answers_to)- Post_answer:a
                ACCUM @@tag_answer_count += (t.tag_name -> 1);
    FOREACH (tag_name, q_count) IN @@tag_question_count DO
        INT a_count = @@tag_answer_count.get(tag_name);
        IF a_count > 0 THEN
            DOUBLE ratio = q_count * 1.0 / a_count;
            @@top_tags += TagStats(tag_name, q_count, a_count, ratio);
        END;
    END;
    PRINT @@top_tags;
}

Equivalent query in GQL standard:

gql
MATCH (t:Tag)-[:Tag_to]->(q:Post_question)
WITH t, count(q) AS question_count
MATCH (t)-[:Tag_to]->(q2:Post_question)<-[:Answers_to]-(a:Post_answer)
WITH t.tag_name AS tag_name,
    question_count,
    count(a) AS answer_count
WHERE answer_count > 0
RETURN tag_name,
    question_count,
    answer_count,
    toFloat(question_count) / toFloat(answer_count) AS ratio
ORDER BY ratio DESC
LIMIT 200;

Q3. Questions with Most Views But No Accepted Answer

Subcategory: T2.1 Node Filtering (Single Node Paths)

This query finds highly viewed questions that do not have an accepted answer recorded, returning each question's ID, view count, and answer count ordered by views.

gsql
CREATE DISTRIBUTED QUERY Query3_unaccepted_high_view_questions(INT limit_count = 200) FOR GRAPH StackOverflow {
    all_questions = {Post_question.*};
    high_view_unaccepted = SELECT q
        FROM all_questions:q
        WHERE q.accepted_answer_id == 0
        ORDER BY q.view_count DESC
        LIMIT limit_count;
    PRINT high_view_unaccepted[
        high_view_unaccepted.id AS question_id,
        high_view_unaccepted.view_count AS view_count,
        high_view_unaccepted.answer_count AS answer_count
    ];
}

Equivalent query in GQL standard:

gql
MATCH (q:Post_question)
WHERE (q.accepted_answer_id IS NULL
    OR q.accepted_answer_id = ''
    OR q.accepted_answer_id = '0'
    OR q.accepted_answer_id = 'None')
RETURN q.id AS question_id,
    toInteger(q.view_count) AS view_count,
    toInteger(q.answer_count) AS answer_count
ORDER BY toInteger(q.view_count) DESC
LIMIT 200;

Q4. Users Who Earn Badges Fastest After Account Creation

Subcategory: T4.4 Grouped Edge Count and Property Statistics

This query groups badge-earning events by user, estimates how many days elapsed between each user's account creation and first badge date, and returns the fastest badge earners.

gsql
CREATE DISTRIBUTED QUERY Query4(INT limit_count = 20) FOR GRAPH StackOverflow {
    MapAccum<STRING, MinAccum<INT>> @@user_min_days;
    MapAccum<STRING, STRING> @@user_display_name;
    all_users = {User.*};
    user_badges = SELECT b
        FROM all_users:u -(Earns)- Badge:b
        ACCUM
            INT days_diff = datetime_diff(b.date, u.creation_date) / 86400,
            @@user_min_days += (u.id -> days_diff),
            @@user_display_name += (u.id -> u.display_name);
    SumAccum<INT> @min_days_attr;
    results = SELECT u
        FROM all_users:u
        WHERE @@user_min_days.containsKey(u.id)
        POST-ACCUM u.@min_days_attr = @@user_min_days.get(u.id)
        HAVING u.@min_days_attr >= 0
        ORDER BY u.@min_days_attr ASC
        LIMIT limit_count;
    PRINT results[
        results.id AS user_id,
        results.display_name,
        results.@min_days_attr AS min_days
    ];
}

Equivalent query in GQL standard:

gql
MATCH (u:User)-[:Earns]->(b:Badge)
WHERE u.creation_date IS NOT NULL
    AND b.date IS NOT NULL
    AND u.creation_date <> ''
    AND b.date <> ''
WITH u.id AS user_id,
     u.display_name AS display_name,
     u.creation_date AS creation_date,
     min(
        (toInteger(substring(b.date, 0, 4)) - toInteger(substring(u.creation_date, 0, 4))) * 365 +
        (toInteger(substring(b.date, 5, 2)) - toInteger(substring(u.creation_date, 5, 2))) * 30 +
        (toInteger(substring(b.date, 8, 2)) - toInteger(substring(u.creation_date, 8, 2)))
     ) AS min_days
WHERE min_days >= 0
RETURN user_id, display_name, min_days
ORDER BY min_days ASC, user_id ASC
LIMIT 20;

Q5. Percentage of Questions Answered Over the Years

Subcategory: Other

This query groups questions by creation year, counts all questions and questions with at least one answer, then returns the yearly answer rate as a percentage.

gsql
CREATE DISTRIBUTED QUERY Query5() FOR GRAPH StackOverflow {
    MapAccum<INT, SumAccum<INT>> @@year_total_questions;
    MapAccum<INT, SumAccum<INT>> @@year_answered_questions;
    all_questions = {Post_question.*};
    yearly_stats = SELECT q
        FROM all_questions:q
        ACCUM
            INT year_val = year(q.creation_date),
            @@year_total_questions += (year_val -> 1),
            IF q.answer_count > 0 THEN
                @@year_answered_questions += (year_val -> 1)
            END;
    FOREACH (year_val, total_questions) IN @@year_total_questions DO
        INT answered_questions = @@year_answered_questions.get(year_val);
        FLOAT answer_rate = answered_questions * 100.0 / total_questions;
        PRINT year_val, total_questions, answered_questions, answer_rate;
    END;
}

Equivalent query in GQL standard:

gql
MATCH (q:Post_question)
WHERE q.creation_date IS NOT NULL
    AND q.creation_date <> ''
WITH substring(q.creation_date, 0, 4) AS year_val,
     count(q) AS total_questions,
     sum(CASE WHEN toInteger(q.answer_count) > 0 THEN 1 ELSE 0 END) AS answered_questions
RETURN year_val,
    total_questions,
    answered_questions,
    round(toFloat(answered_questions) * 100.0 / toFloat(total_questions), 5) AS answer_rate
ORDER BY year_val ASC;

Q6. Top 10 "Easiest" Gold Badges to Earn

Subcategory: T4.4 Grouped Edge Count and Property Statistics

This query focuses on gold badges, counts distinct earners for each badge, estimates the fastest time from account creation to earning that badge, and returns the most commonly earned gold badges.

gsql
CREATE DISTRIBUTED QUERY Query6(INT limit_count = 10) FOR GRAPH StackOverflow {
    MapAccum<STRING, SetAccum<STRING>> @@badge_users;
    MapAccum<STRING, MinAccum<INT>> @@badge_min_days;
    all_users = {User.*};
    user_gold_badges = SELECT b
        FROM all_users:u -(Earns)- Badge:b
        WHERE b.class == "1"
        ACCUM
            @@badge_users += (b.name -> u.id),
            INT days_diff = (datetime_to_epoch(b.date) - datetime_to_epoch(u.creation_date)) / 86400,
            IF days_diff >= 0 THEN
                @@badge_min_days += (b.name -> days_diff)
            END;
    FOREACH (badge_name, user_set) IN @@badge_users DO
        INT total_earners = user_set.size();
        INT min_days = @@badge_min_days.get(badge_name);
        IF min_days < 9223372036854775807 THEN
            PRINT badge_name, total_earners, min_days;
        END;
    END;
}

Equivalent query in GQL standard:

gql
MATCH (u:User)-[:Earns]->(b:Badge)
WHERE b.class = '1'
    AND u.creation_date IS NOT NULL
    AND b.date IS NOT NULL
    AND u.creation_date <> ''
    AND b.date <> ''
WITH b.name AS badge_name,
     count(DISTINCT u.id) AS total_earners,
     min(
        (toInteger(substring(b.date, 0, 4)) - toInteger(substring(u.creation_date, 0, 4))) * 365 +
        (toInteger(substring(b.date, 5, 2)) - toInteger(substring(u.creation_date, 5, 2))) * 30 +
        (toInteger(substring(b.date, 8, 2)) - toInteger(substring(u.creation_date, 8, 2)))
     ) AS min_days
WHERE min_days >= 0
RETURN badge_name, total_earners, min_days
ORDER BY total_earners DESC
LIMIT 10;

Q7. Vote Distribution

Subcategory: T5.1 Degree Centrality

This query ranks users by the total number of votes received across their questions and answers, combining both incoming vote relationships into one activity score.

gsql
CREATE DISTRIBUTED QUERY Query7(INT limit_count = 20) FOR GRAPH StackOverflow {
    SumAccum<INT> @vote_count;    
    // 1. Count votes on questions
    all_questions = {Post_question.*};    
    question_owners = SELECT u
        FROM all_questions:q -(Vote_on_question)- Vote:v,
            all_questions:q -(Owned_by)- User:u
        ACCUM u.@vote_count += 1;    

    // 2. Count votes on answers
    all_answers = {Post_answer.*};    
    answer_authors = SELECT u
        FROM all_answers:a -(Vote_on_answer)- Vote:v,
            all_answers:a -(Answers_by)- User:u
        ACCUM u.@vote_count += 1;    

    // 3. Rank users by total accumulated votes
    all_users = {User.*};
    users_with_votes = SELECT u
        FROM all_users:u
        WHERE u.@vote_count > 0
        ORDER BY u.@vote_count DESC
        LIMIT limit_count;

    PRINT users_with_votes[
        users_with_votes.id AS user_id,
        users_with_votes.display_name,
        users_with_votes.@vote_count AS total_votes
    ];
}

Equivalent query in GQL standard:

gql
MATCH (u:User)
OPTIONAL MATCH (q:Post_question)-[:Owned_by]->(u)
OPTIONAL MATCH (vq:Vote)-[:Vote_on_question]->(q)
WITH u, count(vq) AS q_votes
OPTIONAL MATCH (a:Post_answer)-[:Answers_by]->(u)
OPTIONAL MATCH (va:Vote)-[:Vote_on_answer]->(a)
WITH u.id AS user_id,
     u.display_name AS display_name,
     q_votes + count(va) AS total_votes
WHERE total_votes > 0
RETURN user_id, display_name, total_votes
ORDER BY total_votes DESC
LIMIT 20;

Q8. Most Linked Questions

Subcategory: T5.1 Degree Centrality

This query counts incoming Link_to relationships for each question and returns the questions that are referenced most often by other questions.

gsql
CREATE DISTRIBUTED QUERY Query8(INT limit_count = 20) FOR GRAPH StackOverflow {
    SumAccum<INT> @link_count;
    all_questions = {Post_question.*};
    linked_questions = SELECT q_target
        FROM all_questions:q_source -(Link_to)- Post_question:q_target
        ACCUM q_target.@link_count += 1;

    top_linked = SELECT q
        FROM all_questions:q
        WHERE q.@link_count > 0
        ORDER BY q.@link_count DESC
        LIMIT limit_count;

    PRINT top_linked[
        top_linked.id AS question_id,
        top_linked.@link_count AS link_count
    ];
}

Equivalent query in GQL standard:

gql
MATCH (src:Post_question)-[:Link_to]->(target:Post_question)
WITH target.id AS question_id,
     count(src) AS link_count
WHERE link_count > 0
RETURN question_id, link_count
ORDER BY link_count DESC
LIMIT 20;

Q9. Users Who Comment Most

Subcategory: T5.1 Degree Centrality

This query counts comments authored by each user and returns the most active commenters by total outgoing comment activity.

gsql
CREATE DISTRIBUTED QUERY Query9(INT limit_count = 20) FOR GRAPH StackOverflow {
    SumAccum<INT> @comment_count;
    all_comments = {Comment.*};
    commenters = SELECT u
        FROM all_comments:c -(Commented_by)- User:u
        ACCUM u.@comment_count += 1;
    all_users = {User.*};

    top_commenters = SELECT u
        FROM all_users:u
        WHERE u.@comment_count > 0
        ORDER BY u.@comment_count DESC
        LIMIT limit_count;

    PRINT top_commenters[
        top_commenters.id AS user_id,
        top_commenters.display_name,
        top_commenters.@comment_count AS total_comments
    ];
}

Equivalent query in GQL standard:

gql
MATCH (c:Comment)-[:Commented_by]->(u:User)
WITH u.id AS user_id,
     u.display_name AS display_name,
     count(c) AS total_comments
WHERE total_comments > 0
RETURN user_id, display_name, total_comments
ORDER BY total_comments DESC
LIMIT 20;

Q10. Users with Most Accepted Answers

Subcategory: T5.1 Degree Centrality

This query counts accepted-answer relationships per user and returns the users whose answers were selected as accepted solutions most often.

gsql
CREATE DISTRIBUTED QUERY Query10(INT limit_count = 20) FOR GRAPH StackOverflow {
    SumAccum<INT> @accepted_count;
    // 1. Identify the winners: Question -> Accepted Answer -> Author
    all_questions = {Post_question.*};
    accepted_answer_users = SELECT u
        FROM all_questions:q -(Accepts)- Post_answer:a -(Answers_by)- User:u
        ACCUM u.@accepted_count += 1;

    // 2. Global Rank by solver prestige
    all_users = {User.*};

    top_users = SELECT u
        FROM all_users:u
        WHERE u.@accepted_count > 0
        ORDER BY u.@accepted_count DESC
        LIMIT limit_count;

    PRINT top_users[
        top_users.id AS user_id,
        top_users.display_name,
        top_users.@accepted_count AS accepted_count
    ];
}

Equivalent query in GQL standard:

gql
MATCH (q:Post_question)-[:Accepts]->(a:Post_answer)-[:Answers_by]->(u:User)
WITH u.id AS user_id,
     u.display_name AS display_name,
     count(a) AS accepted_count
WHERE accepted_count > 0
RETURN user_id, display_name, accepted_count
ORDER BY accepted_count DESC
LIMIT 20;