-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for merge join and ordered indexes #4819
Comments
This would be really cool. |
…onnection through to the ExtensibleStore datastructure, without support for inferred statements, ReadCommitted or the caching layers
@hmottestad How will this compare to the existing hash joins? |
The hash joins are used for negation, so it's a bit of a different use case. Merge join is meant to be an alternative to regular join, but faster for large joins. Our current approach is akin to indexed nested loop join, we loop through the left side and do indexed lookups on the right side. With smart read ahead and caching it would be possible to reduce the IO, but worst case we end up with O(N log(N) ) reads from disk with a B+ tree index. With merge join we would do two range queries against the index, so basically O(2) reads. It's not quite true to call it O(2) because the range query reads one block at a time from the B+ tree, so we could call it O(N/K) where K is the size of each block. So it's basically a more optimal way of joining large amounts of data when the underlying store has ordered indexes. Does LMDB have ordered indexes? |
(The hash joins are sometimes used for joins where there are scoping issues, so it's not only for negation.) |
Yes, LmdbStore uses the same indexing scheme as the NativeStore. We also experiment with hash-joins to optimize fetching of time-series data where each property of an item has multiple time-tagged values: |
We should think about how we can pass this about information about sorted iterators on to GROUP BY and ORDER BY operators. e.g. SELECT ?o
WHERE {?s ?p ?o}
ORDER BY ?o If the statementpattern evaluation step/iterarator provides information to order step/iterator we can avoid redoing a lot of work. Same for the GROUP BY, if encounter order is fixed or partially fixed we might avoid building the large hash table. Knowing the order can also help filters. e.g. SELECT ?o
WHERE {?s ?p ?o . FILTER (?o < 10)} If we know that |
Group by is probably the most important one. In the short term it can probably be solved by adding a The order of the index doesn't have to be using the same comparator as SPARQL uses for |
FYI @hmottestad for the readonly sail I am still working on the comparison between the |
We could check if the comparator returned by SailDataset is a ValueComparator instance. |
…onnection through to the ExtensibleStore datastructure, without support for inferred statements, ReadCommitted or the caching layers
Some data sources can return statements in a particular order. Data stored in a B-tree has a natural order due to the natur of a B-tree.
The current join strategy for RDF4J is the iterate over the left data source and for each row create a new iterator from the right data source. This takes advantage the fact that we can bind the result from the left iterator when we create the right iterator, which makes it very selective.
For larger datasets the above approach can cause a lot of IO requests. An example could be that we are joining all
?a a foaf:Person
with?a foaf:age ?age
. If we have 100 000 000 people, then that ends up being 1 000 000 000 new iterators for retrieving the age.Instead we can take advantage of the ordering of the indexes and retrieve:
?a a foaf:Person
from the OPSC index (O and P are constant)?a foaf:age ?age
from the PSOC index (P is constant)These two iterators would both be ordered on the subject (S) variable (?a). We can then do a merge join, which is very efficient both IO wise and memory wise.
This issue aims to:
The text was updated successfully, but these errors were encountered: