AI applicationsGraphRAGAtomic GraphRAGQuery-focused summarization

Query-focused summarization

Query-focused summarization (QFS) answers a question from a summary of the whole dataset, tailored to that question. It’s the GraphRAG pipeline for global questions, such as “What are the main themes?”, where no single node or neighborhood holds the answer.

In a knowledge graph, QFS summarizes the graph’s communities once, then answers each question from the community summaries.

Prerequisites

  • A homogeneous graph: nodes with the same label, connected by relationships. Community detection finds meaningful communities on this kind of graph.
  • A text property on each node, which the summaries are written from.
  • The llm.complete function, configured with your LLM.

Run query-focused summarization

Assign each node to a community. This example uses the Louvain algorithm, and you can use another community detection algorithm:

CALL community_detection.get() YIELD node, community_id
SET node.community_id = community_id;

Summarize each community with the LLM, store the summary on a Community node and connect the community’s members to it:

WITH "You are summarizing a community (cluster)." +
     " Write a concise summary in 2–4 paragraphs that:" +
     " - Captures the main themes and recurring topics." +
     " - Describes the kind of work or concerns this cluster represents." +
     " - Does not list individual entities; synthesize into a coherent narrative."
     AS SUMMARY_TEMPLATE
MATCH (n) WHERE n.community_id IS NOT NULL
WITH n.community_id AS c_id, count(n) AS c_count, collect(n) AS c_members,
     llm.complete(reduce(s=SUMMARY_TEMPLATE, m IN collect(n) | s + m.text + "; ")) AS c_summary
MERGE (community:Community {id: c_id, nodes_count: c_count})
SET community.summary = c_summary
WITH community, c_members
UNWIND c_members AS c_member
MERGE (c_member)-[:BELONGS_TO]->(community)
RETURN community.id AS community_id, community.summary AS community_summary;

To answer a question, ask the LLM how each large community relates to it, then combine the partial answers into one:

WITH "... the question ..." AS USER_QUESTION
// 1. Identify relevant communities (thresholding)
MATCH (c:Community) WHERE c.nodes_count > 5  // only use significant communities
// 2. Map: Generate a partial answer for EACH community
WITH USER_QUESTION, c,
     llm.complete("How does the following community summary: " + c.summary +
                  " relate to: " + USER_QUESTION) AS partial_answer
  WHERE partial_answer IS NOT NULL AND partial_answer <> ""
WITH USER_QUESTION, collect(partial_answer) AS map_results
// 3. Reduce: Synthesize the final consolidated answer
WITH "The following are partial answers from different thematic clusters of " +
     " a dataset. Synthesize them into a single, cohesive response to the " +
     "original query: " + USER_QUESTION +
      "\n\nPartial Answers:\n" +
      reduce(s = "", res IN map_results | s + "- " + res + "\n") AS reduce_prompt
RETURN llm.complete(reduce_prompt) AS final_answer;