跳到正文
DEV Community· NIKITHA·· 4 小時前AI 評分43

FalkorDB 以 Edgemaxxing 設計勝過 Joins

We went Edgemaxxing and FalkorDB mogged Joins

AI 導讀

這套應用採用 FalkorDB 的 Edgemaxxing 設計,將證據立場與矛盾關係連到各自假設,避免為不同假設重複複製研究發現。FalkorDB 支援邊屬性、邊索引及內置 algo.WCC;重用已讀論文可節省 LLM 成本和時間。

正文

Here is how we did it, Edgemaxxing is really good (for performance).


Background you need first

What is a graph database?

A graph database stores two things:

  • Nodes: things. For example: a paper, a finding, a hypothesis.
  • Edges: connections between two things. For example: "this finding is evidence for this hypothesis".

Both nodes and edges can hold properties, which are small pieces of data such as year: 2026 or stance: "refutes".

FalkorDB is a graph database. You talk to it with a query language called Cypher. A Cypher pattern looks like a drawing:

(finding)-[:EVIDENCE_FOR]->(hypothesis)

That reads as "a finding, connected by an EVIDENCE_FOR edge, to a hypothesis".

Terms

These are relevant to the problems we are solving so its good to know, But it should work generally for other use cases as well!

Word Meaning Example
Question What the user types "creatine on intelligence vs muscle gain"
Hypothesis One testable claim from the question H2: "Creatine increases muscle gain in adults"
Paper A published article Chen 2026 (a meta-analysis)
Study One experiment inside a paper An RCT with 15 vegans
Finding One measured result from a study "Skeletal muscle mass: no change"
Concept A topic or measurement "lean mass"

Part 1: Edgemaxxing begins

The problem

Lets look at an example "Lean mass increased by 0.37 kg."

  • For a hypothesis H2 (creatine increases muscle gain), this finding supports it.
  • For a different hypothesis, such as "creatine harms kidneys", it is not relevant.

So "supports" is not a fact about the finding alone. It is a fact about the finding together with one hypothesis.

The bad solution

Store stance: "supports" on the finding node. Then the second hypothesis breaks: it sees "supports" too, which is wrong. You would have to copy the finding once per hypothesis, and the copies would drift apart.

What we did

We put the stance on the edge between the finding and the hypothesis i.e Edgemaxxing:

(Finding: "Lean mass ↑ 0.37 kg") -[:EVIDENCE_FOR {stance: "supports", weight: 0.67}]-> (H2)
  • There is one finding node.
  • There is one edge per hypothesis, and each edge has its own stance.

On the finding, “supports” can't say which hypothesis it means. On the edge, it can.

Relevant bit: many databases can't store properties on a connection, or make it awkward. FalkorDB is a property graph, so edges can hold data just like nodes can. This one feature makes the whole design possible.

Why this matters

Papers and findings are shared across all questions. When a new question needs a paper that was already read, the app does not read it again. It only adds new EVIDENCE_FOR edges. That saves LLM cost and time.


Part 2: Make each contradiction an edge, tied to one hypothesis

The problem

Two findings can disagree for one hypothesis and not for another.

  • For a hypothesis H2, "lean mass ↑" (Naddafha 2026) and "skeletal muscle mass: no change" (Chen 2026) disagree.
  • For a kidney hypothesis, the same two findings say nothing, so there is no disagreement.

What we did

Edgemaxxing again! A contradiction is an edge between two findings, and it records which hypothesis it belongs to:

(Naddafha finding) -[:CONTRADICTS {hypothesis: "H2", reason: "different population",
                                   explained_by: "postmenopausal women vs all women"}]-> (Chen finding)

The query:

MERGE (a)-[e:CONTRADICTS {hypothesis:$k}]->(b)
SET e.reason = ..., e.severity = ..., e.explained_by = ...

Relevant bit: MERGE means "create it only if it does not exist yet".

The index

To show the contradictions for H2, the app asks: "give me every CONTRADICTS edge where hypothesis = H2". Without help, FalkorDB would have to check every contradiction edge in the whole graph.

So we created an index on that edge property:

CREATE INDEX FOR ()-[r:CONTRADICTS]-() ON (r.hypothesis)

Relevant bit: an index is like the index at the back of a book. Instead of reading every page, you jump straight to the right page. Most databases only index nodes or rows. FalkorDB can also index edges, which is what makes this lookup fast.


Part 3: Recognise the same outcome under different names

The problem

Paper A says "fat-free mass". Paper B says "lean body mass". Paper C says "FFM". These are almost the same measurement. If the app only matched exact words, it would miss real disagreements between these papers.

What we did

  1. Each Concept node has a synonyms list (other names for the same thing).
  2. When the Stance agent (an LLM) judges a finding, it also answers: "does this finding measure the hypothesis's outcome, even under another name?" (same_outcome: true/false).
  3. If yes, the code adds a special edge from the finding to the hypothesis's own outcome concept:
   (Finding: "FFM ↑ 1.15 kg") -[:MEASURES {hypothesis: "H2"}]-> (Concept: "muscle gain")
  1. The code also adds the finding's wording to the concept's synonyms. Next time, "FFM" is already known as a name for that outcome, with no LLM needed.

Relevant bit: this MEASURES edge also carries hypothesis, for the same reason as Part 2: "FFM counts as muscle gain" is true for H2, but maybe not for some other hypothesis. It has an edge index too. Again Edgemaxxing!!!!!

Why this matters

The graph learns names over time. Every question makes the synonym lists better for the next question.


Part 4: Contradiction camps with algo.WCC

What it does

Imagine the contradiction edges as strings tied between findings:

  • If A contradicts B, and B contradicts C, then A, B and C are all tied together.
  • Each group of tied-together findings is one "camp": one area where the evidence argues with itself.

WCC ("weakly connected components") is the standard algorithm that finds these groups.

Relevant bit: FalkorDB ships graph algorithms built in, so the app calls CALL algo.WCC(...) inside the database. It doesn't have to download the whole graph and run the algorithm in Python.

The query:

CALL algo.WCC({nodeLabels: ['Finding'], relationshipTypes: ['CONTRADICTS']})
YIELD node, componentId
MATCH (node)-[e:EVIDENCE_FOR]->(h:Hypothesis)<-[:ASKS]-(:Question {id:$q})
WITH h, componentId, count(DISTINCT node) AS findings, collect(DISTINCT e.stance) AS stances
WHERE findings > 1
RETURN h.statement AS hypothesis, componentId AS camp, findings, stances

In plain words: find the camps across all findings, then keep only the ones in this question, and show each camp's size and stances.

One limitation: WCC runs over all CONTRADICTS edges, for every hypothesis. If one finding has contradictions under two different hypotheses, those two camps can join into one.


How it all fits together

Paper ─DESCRIBES→ Study ─FOUND→ Finding ─EVIDENCE_FOR {stance}→ Hypothesis
                                   │
                                   ├─MEASURES {hypothesis}→ Concept {synonyms}
                                   │
                                   └─CONTRADICTS {hypothesis, reason, explained_by}→ Finding

Parting Notes

Edges are the core feature of graph dbs. Using them effectively can make your life easier (and faster!!!).

來源:DEV Community · dev.to