core-logic

2018-09-05T11:06:06.000100Z

Are there any docs on tabling in core.logic and how it works?

2018-09-05T11:13:20.000100Z

Backstory: I’ve implemented a SPARQL/Datalog-like query DSL for querying in memory RDF graphs with core.logic. The DSL essentially tries to hide a lot of the minikanren/relational-programming stuff and present a simpler “SPARQL like” model, where you don’t need to fresh variables etc… I use db-rel to get acceptable performance. Currently I compile the Basic Graph Pattern vectors my macro receives and convert them to calls to db-rel. What I have works quite well, but it does of course mean that you can’t generate queries at runtime. I’d like to explore doing the same but with functions, so I can also provide a way to build tabled queries dynamically. Is this possible?

2018-09-05T11:13:39.000100Z

For reference this is the project: https://github.com/Swirrl/matcha

2018-09-05T11:40:09.000100Z

e.g. the graph pattern [[:foo ?p ?o]] would currently compile into something like:

2018-09-05T11:40:11.000100Z

(clojure.core.logic/fresh
          [?p ?o]
          (grafter.matcha.alpha/triple ?s ?p ?o))

2018-09-05T11:43:26.000100Z

I can obviously define a relation that will recursively apply the triple relation, but won’t that eliminate the advantages of indexing? I’m also not entirely sure of all the semantics around using clojure inside relations etc, which was my first instinct to avoid using a macro.

bajrachar 2018-09-05T15:32:27.000100Z

@rickmoynihan - sounds like an interesting project - It would be great to have something to query in-memory graph - without digging into minikanren

bajrachar 2018-09-05T15:32:45.000100Z

I didn't quite follow what you mean by generating queries dynamically

bajrachar 2018-09-05T15:33:58.000100Z

I recently also used core.logic for graph traversal - but due to large size of the db it wasnt as efficient

2018-09-05T15:34:52.000100Z

Sometimes you want to generate queries dynamically based on inputs. Currently in Matcha you can’t do this kinda thing: (let [query-pattern (conj '[?s ?p] '?o)] ((select query-pattern) friends)

2018-09-05T15:35:54.000100Z

because select is a macro, so query-pattern has to be hardcoded as a literal value at compile time

bajrachar 2018-09-05T15:45:52.000200Z

ok I see what you mean - how does tabling help in this scenario?

2018-09-05T15:46:12.000100Z

it makes it orders of magnitude faster

bajrachar 2018-09-05T15:48:19.000100Z

and you want to use functions in place of macro

bajrachar 2018-09-05T15:48:53.000100Z

sorry - just trying to understand the problem 🙂 -

bajrachar 2018-09-05T16:05:08.000100Z

I don't know if it is applicable in this particular case - but for my particular use case of making graph traversal faster on a very large in-memory db - I went about re-writing some parts of pldb and db-rel

bajrachar 2018-09-05T16:07:25.000100Z

making the matching logic parallel - which seemed to work better than tabling

bajrachar 2018-09-05T16:07:52.000100Z

as issue for me wasn't that query was diverging

2018-09-05T16:17:58.000100Z

> and you want to use functions in place of macro @bajrachar Yes.

2018-09-05T16:31:43.000200Z

I think the problem is that without tabling I’d need to scan the database on each join, so performance becomes exponential?/quadratic?/something-really bad. Making it parallel might help, but at best parallelisation will only make linear gains in terms of processors; rather than the orders of magnitude gains you can get through indexing/tabling/memoization/better-algorithms. For me querying just 1000 edges was taking my naive version longer than querying millions of edges with tabling

bajrachar 2018-09-05T16:57:56.000100Z

sounds interesting - definitely would like to see how you've used tabling

bajrachar 2018-09-05T16:58:56.000100Z

by join - I assume its traversing the graph to depth n?

2018-09-05T18:21:20.000100Z

I mean join in the RDBMS sense. Effectively a triple store is a single table with three columns; every time you walk from one edge (row) to another through a ?variable binding you’re effectively doing a self join back on that table. But yes each traversal is effectively another join.

2018-09-05T18:34:25.000100Z

I think I understand roughly how this works; but need to figure out the finer details

2018-09-05T18:35:08.000100Z

the second link in the source code 404's 😞

2018-09-05T18:36:15.000100Z

I think the first link is Byrds thesis… I’ve skimmed this before; but can’t recall the details of tabling

2018-09-05T19:36:46.000100Z

hmmm… maybe I’m misunderstanding the relationship between tabling and pldb