Schema Diagram and Graph Statistics
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.
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.
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"
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"
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"
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"
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"
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"
CREATE VERTEX Vote ( PRIMARY_ID id STRING, creation_date DATETIME, post_id INT, vote_type_id INT ) WITH primary_id_as_attribute="true"
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"
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.
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.
USE GRAPH StackOverflow
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
Q1. User Pairs with Most Question-Answer Interactions
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.
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:
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
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.
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:
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
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.
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:
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
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.
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:
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
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.
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:
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
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.
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:
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
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.
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:
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
This query counts incoming Link_to relationships for each question and returns the
questions that are referenced most often by other questions.
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:
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
This query counts comments authored by each user and returns the most active commenters by total outgoing comment activity.
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:
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
This query counts accepted-answer relationships per user and returns the users whose answers were selected as accepted solutions most often.
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:
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;