BuildNot yet confirmed elsewhere1 publisher3 min readPublished
A depth-bounded Cypher path returns each ASML supply link with the article that established it
Multi-hop supply questions are cheap to ask in Cypher and awkward everywhere else. The traversal only holds if every article's name for a company lands on the same node. The post breaks off before that gets solved.
The Engineer · Build desk

What happened
- The build log's working query is Cypher: it matches SUPPLY_CUT, EXPORT_RESTRICTION and PRODUCTION_DELAY edges one to four hops out from ASML and returns each path with the article ID and event date on every link.
- The full-text attempt over an Elasticsearch index of 9,414 English economic news articles returned fourteen hits, none of them the NVIDIA articles, because NVIDIA is not mentioned in any of the fourteen.
- The relational attempt stored one row per event in an article_events table, which meant one CTE per hop and a hop count that had to be fixed before the query ran.
Why it matters
- constraint A fixed-hop SQL query cannot report that it stopped early, so a five-link chain and a chain that does not exist return the same empty result and the same false comfort.
- decision Choosing traversal promotes entity resolution from housekeeping to a build-time dependency, because every unresolved alias truncates paths that would otherwise connect.
- exposure At roughly 29 extracted edges per article with no published precision, the people relying on this graph are exposed to single bad extractions that surface as paths with article IDs attached.
- capability Because depth is a query-time parameter, re-asking the same supply-chain question at six hops costs a keystroke rather than a schema change and a rewrite.
Run the pattern and Neo4j hands back path objects rather than tuples [1][2]. The load-bearing part is not the variable-length arrow, it is the two list comprehensions in the RETURN clause: `[r IN relationships(path) | r.article_id]` walks every edge of a matched path and pulls the article that established it, and its sibling does the same for `event_date` [1]. A four-hop result therefore arrives carrying four article IDs and four dates, one per link, instead of a single provenance stamp on the endpoint [2]. With the `LIMIT 30` in place, one run can return up to 120 article references for a human to check [23].
The two attempts that failed did so for unrelated reasons, which is easy to lose in the retelling. Elasticsearch was asked a question about text and answered it: fourteen documents matched the phrasing, and the NVIDIA articles were not among them because NVIDIA is not named in any of them [6][7]. The author is explicit that relevance tuning would not have closed that gap [7]. SQL failed on two counts. The visible one is hop count, two CTEs for two hops, three for three, depth fixed before the query runs [10]. The quieter one is arity: an article describing an event involving three or four companies does not reduce to one subject-object row without discarding something [13]. Worth noting that the Cypher pattern also runs company to company [1], so a four-participant event still has to be decomposed into pairwise edges or into an event node the post does not show. The graph relaxes the row shape, but modeling an event with four participants takes more structure than that alone provides [13].
The ratios are worth doing. 275,293 relationships over 9,414 articles is 29.2 edges per article [19]; 84,962 nodes over the same corpus is 9.0 nodes per article [20]; the graph averages 3.2 relationships per node [21]. That density is a claim about an extraction pipeline, not about Neo4j. For it to transfer, your articles would have to name companies at a similar rate and your extractor would have to be as willing to emit an edge. No precision figure is reported for any of the 275,293 [14], and a bad edge does not look bad in the output; it looks like a path with an article ID attached [2].
Latency is the figure missing here. Response time on the Cypher query is described as acceptable, but the post gives no number, no hardware detail, and no comparison against a deeper bound [15]. A benchmark table would at least be something to argue with. What the post does name as the unfinished dependency is entity resolution: the traversal only works if the same company maps to the same node however an article refers to it, and that did not happen automatically [17]. Filings say ASML Holding NV, a wire shortens it to ASML, and a blog post never names the company and calls it the Dutch lithography equipment maker [18]. Left unresolved those are three nodes, and the source text breaks off mid-sentence on exactly that failure [24].
The semantics of an empty result are stated carefully, and that carries more weight than it sounds: no path returned means the graph holds no evidence for the connection, not that the connection is absent in the world [16]. Combined with a depth bound tuned at query time [3], that supports an honest workflow. Ask at four hops, ask at six, and read both answers as statements about corpus coverage rather than about semiconductors. It also means the graph inherits every gap in the 9,414 articles [5], which is a fair trade for a research tool and a poor one for anything that has to be right before someone opens the cited articles.
What to watch
- Whether part 3 resolves entities with a deterministic alias table or embedding-based coreference, and what that does to the 84,962 node count.
- Any reported precision figure for the extracted relationships, since one wrong edge produces a path that reads like sourced evidence.
- A measured latency number at depth five or six on the same graph, which is where variable-length expansion normally starts to hurt.
Clarity's read
What the record supports and how the coverage leans. The claims behind it follow.
Reality
- Evidence52
- Adoption12
- Hype gap+10
- Incentives32
- Confidence55
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
The working query is Cypher: MATCH path = (source:Company {name: "ASML"}) -[:SUPPLY_CUT|EXPORT_RESTRICTION|PRODUCTION_DELAY*1..4]-> (downstream:Company), returning downstream.name, length(path) as hops, [r IN relationships(path) | r.article_id] as evidence_articles and [r IN relationships(path) | r.event_date] as event_dates, ordered by hops and first event date, LIMIT 30. The pattern runs company node to company node.
- [2]
The author states the query returns paths, not rows: each result is a chain from the source company to a downstream company with the article ID and event date at every link, not just at the endpoint.
- [3]
The *1..4 depth bound is a parameter the author tunes at query time; checking four hops required no rewriting.
- [4]
The author says he did not write the Cypher query first: it is where he ended up after trying two other things that did not work.
- [5]
The article database sits in Elasticsearch, in an index called economic_news_articles_en, currently holding 9,414 documents.
- [6]
An Elasticsearch bool query matching the text "chip packaging export restriction" with published_at >= 2023-01-01 and size 15 returned fourteen results; some were on the specific restriction and a few matched incidentally.
- [7]
The NVIDIA articles were absent from those fourteen results because NVIDIA is not mentioned in any of them; the author says this is not a deficiency in Elasticsearch, that the index does not model edges, and that relevance tuning would not have helped.
- [8]
The relational attempt used an article_events table generated during the build, each row holding an event type, a subject company, an affected company and a date.
- [9]
The first SQL query joined article_events to companies where subject_id was ASML and event_type was in supply_cut, export_restriction or production_delay, giving first-hop results only.
- [10]
The two-hop version wrapped the first hop in a CTE and joined article_events again with ae2.event_date >= fh.event_date; the author notes two CTEs for two hops, three for a three-hop query, and that he had to know upfront how many hops he was looking for.
- [11]
The author notes that if the connection he cares about is five steps deep, a three-hop query misses it quietly.
- [12]
The author says recursive CTEs handle variable depth but bring their own performance questions, and that by that point he was building something that was not really a SQL use case.
- [13]
The author says the relational schema was losing information: events in articles do not always have clean subject-object pairs, and an article might describe an event involving three or four companies in ways he could not reduce to one row without discarding something.
- [14]
The graph at this point holds 84,962 nodes and 275,293 relationships, built from the same 9,414 articles. No precision or accuracy figure is reported for the extracted relationships.
- [15]
The author states only that response time on the Cypher query is acceptable; the post gives no latency figure, no comparison at greater depth and no hardware description.
- [16]
The author states that when a path does not exist in the data the query returns nothing, which is a correct answer: it means the graph lacks evidence for that connection, not that the connection does not exist in the world.
- [17]
The author says that for the traversal to be useful the same company had to map to the same node regardless of how different articles referred to it, and that this did not happen automatically.
- [18]
The author gives three naming variants for one company: a formal announcement saying "ASML Holding NV", a wire service shortening it to "ASML", and a blog post that never names the company and calls it "the Dutch lithography equipment maker".
- [19]
The graph averages 29.2 relationships per source article.
- [20]
The graph averages 9.0 nodes per source article.
- [21]
The graph averages 3.2 relationships per node.
- [22]
Matching the Cypher query's four-hop bound in the SQL shape would require four stacked CTE tiers, since the author reports one CTE per hop.
- [23]
At the maximum depth bound, a single run of the query can return up to 120 evidence article references.
- [24]
The supplied source text ends mid-sentence while describing what happens if those naming variants land as three separate nodes in the graph.
Sources
1 independent publisher whose own reporting we read for this story.
- dev.toBuilding an investing knowledge graph, part 2: the query SQL can't answer
1 article · August 28, 2026
Topics and entities
Follow any of these and your For You feed starts watching them — no settings page required.
Topics
- Graph query languagesFollow
- Knowledge GraphsFollow
- Search versus traversalFollow
- Entity resolutionFollow
- Supply chain intelligenceFollow