fix(graph): resolve cited_id to papers.id via openalex_id JOIN
build_citation_graph now does: SELECT c.citing_id, COALESCE(p.id, c.cited_id) AS cited_id FROM citations c LEFT JOIN papers p ON p.openalex_id = c.cited_id Before: cited_id (OpenAlex IDs) never matched papers.id (DOIs) → 13 cross-citations between ingested papers were invisible in graph. After: in-KB papers use their canonical DOI key; dangling references keep their raw OpenAlex ID unchanged. Test: test_cross_citation_uses_doi_when_in_kb (42 passed). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,11 @@ def build_citation_graph(conn: Any) -> nx.DiGraph:
|
|||||||
the citing paper references the cited paper. Both ingested papers
|
the citing paper references the cited paper. Both ingested papers
|
||||||
and dangling targets (cited but not yet ingested) appear as nodes.
|
and dangling targets (cited but not yet ingested) appear as nodes.
|
||||||
|
|
||||||
|
``cited_id`` in the citations table stores OpenAlex IDs; ``papers.id``
|
||||||
|
stores DOIs. A LEFT JOIN resolves cited papers that are in the KB to
|
||||||
|
their canonical DOI key via ``papers.openalex_id``. Dangling references
|
||||||
|
(not in KB) keep their raw OpenAlex ID.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
conn:
|
conn:
|
||||||
@@ -40,7 +45,13 @@ def build_citation_graph(conn: Any) -> nx.DiGraph:
|
|||||||
-------
|
-------
|
||||||
nx.DiGraph with every (citing_id, cited_id) pair as an edge.
|
nx.DiGraph with every (citing_id, cited_id) pair as an edge.
|
||||||
"""
|
"""
|
||||||
rows = conn.execute("SELECT citing_id, cited_id FROM citations").fetchall()
|
rows = conn.execute(
|
||||||
|
"""
|
||||||
|
SELECT c.citing_id, COALESCE(p.id, c.cited_id) AS cited_id
|
||||||
|
FROM citations c
|
||||||
|
LEFT JOIN papers p ON p.openalex_id = c.cited_id
|
||||||
|
"""
|
||||||
|
).fetchall()
|
||||||
g: nx.DiGraph = nx.DiGraph()
|
g: nx.DiGraph = nx.DiGraph()
|
||||||
for row in rows:
|
for row in rows:
|
||||||
g.add_edge(row["citing_id"], row["cited_id"])
|
g.add_edge(row["citing_id"], row["cited_id"])
|
||||||
|
|||||||
@@ -80,6 +80,24 @@ class TestBuildCitationGraph:
|
|||||||
g = build_citation_graph(_make_conn(rows))
|
g = build_citation_graph(_make_conn(rows))
|
||||||
assert "not_in_papers" in g.nodes()
|
assert "not_in_papers" in g.nodes()
|
||||||
|
|
||||||
|
def test_cross_citation_uses_doi_when_in_kb(self):
|
||||||
|
# Simulate DB COALESCE: cited_id already resolved to papers.id (DOI)
|
||||||
|
# for in-KB papers; dangling references keep their OpenAlex ID.
|
||||||
|
rows = [
|
||||||
|
{
|
||||||
|
"citing_id": "https://doi.org/10.1234/paper-a",
|
||||||
|
"cited_id": "https://doi.org/10.5678/paper-b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"citing_id": "https://doi.org/10.5678/paper-b",
|
||||||
|
"cited_id": "https://openalex.org/W999",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
g = build_citation_graph(_make_conn(rows))
|
||||||
|
assert g.has_edge("https://doi.org/10.1234/paper-a", "https://doi.org/10.5678/paper-b")
|
||||||
|
assert g.has_edge("https://doi.org/10.5678/paper-b", "https://openalex.org/W999")
|
||||||
|
assert g.number_of_nodes() == 3
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# citation_pagerank
|
# citation_pagerank
|
||||||
|
|||||||
Reference in New Issue
Block a user