TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Representing Graphs in PostgreSQL

193 点作者 gsky3 个月前

16 条评论

osigurdson3 个月前
It is always good to know, at what point does "Postgres as X" break down. For instance, I know from experience that Postgres as timeseries DB (without add-ons) starts to break down in low billions of rows. It would be great to know that for graph DBs as well. I think a lot of people would prefer just to use Postgres if they can get away with it.
评论 #43079226 未加载
评论 #43079418 未加载
评论 #43079660 未加载
评论 #43079434 未加载
评论 #43079210 未加载
评论 #43090682 未加载
评论 #43079396 未加载
评论 #43079309 未加载
eatonphil3 个月前
I thought this was going to be about querying a Postgres table with a graph query language (SQL&#x2F;PGQ).<p>Indeed this is coming to Postgres eventually.<p><a href="https:&#x2F;&#x2F;www.postgresql.org&#x2F;message-id&#x2F;flat&#x2F;a855795d-e697-4fa5-8698-d20122126567%40eisentraut.org" rel="nofollow">https:&#x2F;&#x2F;www.postgresql.org&#x2F;message-id&#x2F;flat&#x2F;a855795d-e697-4fa...</a><p><a href="https:&#x2F;&#x2F;ashutoshpg.blogspot.com&#x2F;2024&#x2F;04&#x2F;dbaag-with-sqlpgq.html" rel="nofollow">https:&#x2F;&#x2F;ashutoshpg.blogspot.com&#x2F;2024&#x2F;04&#x2F;dbaag-with-sqlpgq.ht...</a>
评论 #43078952 未加载
评论 #43079050 未加载
Epa0953 个月前
There is also <a href="https:&#x2F;&#x2F;age.apache.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;age.apache.org&#x2F;</a>, an extension to facilitate graph queries in postgresql.
评论 #43078480 未加载
评论 #43078412 未加载
yonisto3 个月前
This time it must be me... Bilbo is not Frodo&#x27;s father (Frodo is actually Bilbo&#x27;s first and second cousin, once removed)
评论 #43079298 未加载
评论 #43078780 未加载
pella3 个月前
If you need some &quot;Routing Graph&quot; - check the pgRouting library <a href="https:&#x2F;&#x2F;pgrouting.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;pgrouting.org&#x2F;</a><p><pre><code> &quot;pgRouting library contains following features: All Pairs Shortest Path, Johnson’s Algorithm All Pairs Shortest Path, Floyd-Warshall Algorithm Shortest Path A* Bi-directional Dijkstra Shortest Path Bi-directional A\* Shortest Path Shortest Path Dijkstra Driving Distance K-Shortest Path, Multiple Alternative Paths K-Dijkstra, One to Many Shortest Path Traveling Sales Person Turn Restriction Shortest Path (TRSP)&quot;\* </code></pre> see more: <a href="https:&#x2F;&#x2F;docs.pgrouting.org&#x2F;latest&#x2F;en&#x2F;pgRouting-concepts.html#graphs" rel="nofollow">https:&#x2F;&#x2F;docs.pgrouting.org&#x2F;latest&#x2F;en&#x2F;pgRouting-concepts.html...</a>
评论 #43079302 未加载
t435623 个月前
ltree is the one I ended up using. I don&#x27;t like it much. The way it works allows you to setup a tree but you can&#x27;t easily move things around within a tree once they&#x27;re in.<p>I forgot to say that it&#x27;s also obviously only a tree, not a graph. It&#x27;s still useful for some cases.<p>It has a very good way of querying which is probably fast if you have very deep trees but in the end we didn&#x27;t need the deep trees so it was chosen for the wrong reasons.<p><a href="https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;ltree.html" rel="nofollow">https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;ltree.html</a><p>You essentially have a path field in your record which lists the ids of all the records that are parents of the current one plus the current one.<p>e.g. if your records are regions of the world and the id is the country name then the path might look like this:<p>Earth.Europe.Poland<p>There is support for queries like &quot;what are all the descendants of Europe&quot;<p><pre><code> SELECT name FROM regions WHERE path &lt;@ &#x27;Earth.Europe&#x27;; </code></pre> Or you can use matching:<p><pre><code> SELECT name FROM regions WHERE path ~ &#x27;*.Europe.*&#x27;;</code></pre>
simpaticoder3 个月前
&quot;CTE&quot; refers to Postgres&#x27; &quot;common table expression&quot; syntax, the &quot;WITH&quot; keyword. See <a href="https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;queries-with.html" rel="nofollow">https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;queries-with.html</a>
评论 #43079408 未加载
voodooEntity3 个月前
Im a big fan of GraphDatabase&#x27;s since about 10 years. I even wrote my own &quot;in memory graph storage&quot; in golang for a specific use case that none of the big GraphDatabase&#x27;s could cover at the time.<p>That said - i WISH people would embrase the existing GraphDatabases more and make the hosters support them as standard, rather than abusing existing relational databases for graph purposes.<p>And to make it clear,i&#x27;m not talking about my own experimental one, i mean stuff like Neo4j, OrientDB etc.
评论 #43078972 未加载
评论 #43078755 未加载
评论 #43079397 未加载
评论 #43078799 未加载
gjtorikian3 个月前
It’s a neat trick! A simpler choice would be to use Postgres’ own ltree data type: <a href="https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;15&#x2F;ltree.html" rel="nofollow">https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;15&#x2F;ltree.html</a><p>I wrote about how we use it here: <a href="https:&#x2F;&#x2F;www.yetto.app&#x2F;blog&#x2F;post&#x2F;how-labels-work&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.yetto.app&#x2F;blog&#x2F;post&#x2F;how-labels-work&#x2F;</a>
评论 #43079655 未加载
robertclaus3 个月前
I&#x27;ve found the main advantage to this over a more specialized graph database is integration and maintenance alongside the rest of your application. Real world data is rarely just (or even mostly) graph data.
wslh3 个月前
If you are interested in the subject, also take a look at NetworkDisk[1] which enable users&#x2F;devs of NetworkX[2] to work with graphs via SQLite.<p>[1] <a href="https:&#x2F;&#x2F;networkdisk.inria.fr&#x2F;" rel="nofollow">https:&#x2F;&#x2F;networkdisk.inria.fr&#x2F;</a><p>[2] <a href="https:&#x2F;&#x2F;networkx.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;networkx.org&#x2F;</a>
ForHackernews3 个月前
Surprised to see this article with no mention of LTree: <a href="https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;ltree.html" rel="nofollow">https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;ltree.html</a><p>First-party data structure for tree (directed, acyclic graph) data
dangoodmanUT3 个月前
This is where you start to see major limitations of OLTP, and need to look at specialized graph DBs (or indexes really) that take advantage of index-free adjacency
hknlof13 个月前
At DuckCon #6 there was a talk given about implementing SQL&#x2F;PGQ as an extension to DuckDB<p><a href="https:&#x2F;&#x2F;m.youtube.com&#x2F;watch?v=QDdTbhSR2Vo" rel="nofollow">https:&#x2F;&#x2F;m.youtube.com&#x2F;watch?v=QDdTbhSR2Vo</a><p><a href="https:&#x2F;&#x2F;duckdb.org&#x2F;community_extensions&#x2F;extensions&#x2F;duckpgq.html" rel="nofollow">https:&#x2F;&#x2F;duckdb.org&#x2F;community_extensions&#x2F;extensions&#x2F;duckpgq.h...</a>
评论 #43079452 未加载
jakozaur3 个月前
There was a very good discussion about PostgreSQL as graph database on Hacker News about a year ago: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=35386948">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=35386948</a>
zamalek3 个月前
This doesn&#x27;t seem to cover infinite recursion, which is one of the ugliest parts of doing this type of query with CTEs. You effectively need to concatenate all of the primary keys you&#x27;ve seen into a string, and check it each recursive iteration.<p>The approach I came up with was to instead use MSSQL hierarchy IDs (there&#x27;s a paper describing them, so they can be ported to any database). This specifically optimizes for ancestor-of&#x2F;descendant-of queries. The gist of it is:<p>1. Find all cycles&#x2F;strong components in the graph. Store those in a separate table, identifying each cycle with an ID. Remove all the nodes in the cycle, and insert a single node with their cycle ID instead (turning the graph into a DAG). The reason we do this is because we will always visit every node in a cycle when doing an ancestor-of&#x2F;descendant-of query.<p><pre><code> +---+ +-------&gt; B +------+ +-+-+ +-^-+ +-v-+ | A | | | C | +---+ | +-+-+ +-+-+ | | D &lt;------+ +---+ </code></pre> Becomes:<p><pre><code> +---+ +---+ | A +--&gt; 1 | +---+ +---+ +---+---+ | 1 | B | | 1 | C | | 1 | D | +---+---+ </code></pre> 2. You effectively want to decompose the DAG into a forest of trees. Establish a worklist and place all the nodes into it. The order in this worklist may be something that can affect performance (you want the deepest&#x2F;largest tree first). Grab nodes out of this worklist and perform a depth-first search, removing nodes from the worklist as you traverse them. These nodes can then be inserted into the hierarchy ID table. You should insert all child nodes of each node, even if it has already been inserted before, but only continue traversing downwards if the node hasn&#x27;t yet been inserted.<p><pre><code> +---+ +----&gt; B +----+ +-+-+ +---+ +-v-+ +---+ | A | | D +--&gt; E | +-+-+ +-^-+ +---+ | +---+ | +----&gt; C +----+ +---+ </code></pre> Becomes:<p><pre><code> +---+ +---+ +---+ +---&gt; B +--&gt; D +--&gt; E | +-+-+ +---+ +---+ +---+ | A | +-+-+ +---+ +---+ +---&gt; C +--&gt; D | +---+ +---+ </code></pre> Or, as hierarchy IDs<p><pre><code> A &#x2F;1 B &#x2F;1&#x2F;1 D &#x2F;1&#x2F;1&#x2F;1 E &#x2F;1&#x2F;1&#x2F;1&#x2F;1 C &#x2F;1&#x2F;2 D &#x2F;1&#x2F;2&#x2F;1 </code></pre> Now, you do still need a recursive CTE - but it&#x27;s guaranteed to terminate. The &quot;interior&quot; of the CTE would be a range operation over the hierarchy IDs. Basically other.hierarchy &gt;= origin.hierarchy &amp;&amp; other.hierarchy &lt; next-sibling(origin.hierarchy) (for descendant-of queries). You need to recurse to handle situations involves nodes like D in the example above (if we started at C, we&#x27;d get D in the first iteration, but would need to recurse to the first D node in order to find E).<p>This was two orders of magnitude faster than a recursive CTE using strings to prevent infinite recursion.<p>The major disadvantage of this representation is that you can&#x27;t modify it. It has to be calculated from scratch each time a node in the graph is changed. The dataset I was dealing with was 100,000s of nodes for each customer, took under a second, so that wasn&#x27;t a problem. You could probably also identify changes that don&#x27;t require a full rebuild (probably any change that doesn&#x27;t involve a back edge or cross edge), but I never had to bother so didn&#x27;t solve it.