You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
require(data.table)
dt= data.table(id="x", a=as.integer(c(3,8,8,15,15,15,16,22,22,25,25)), b=as.integer(c(9,10,25,19,22,25,38,3,9,7,28)), c=as.integer(c(22,33,44,14,49,44,40,25,400,52,77)))
dt[.(a=c(12,20), b=20), sum(c), on=c("a>a", "b<=b"), by=.EACHI]
# Error in `[.data.table`(dt, .(a = c(12, 20), b = 20), sum(c), on = c("a>a", : # by-joins are not yet implemented for multi-group non-equi-joins.
The idea for non-equi joins is to split data.table x (here, dt) into groups where rows of all columns, independently, have values always in increasing order. Here, there'll be more than one such "group". In the examples you've worked so far, there must have been only one such group. If this is hard to follow, please wait a while. I'll have better explanations (with visualisations) for UseR'16 soon.
Ok, thanks, so failure is actually catastrophic and not silent. That's good - I thought it just works incorrectly for some cases and was looking for an incorrect result.
Iirc the cases I've worked with all had a single column on LHS, which always satisfies the single group condition.
@ywhuofu if you want inequality join like in SQL then why you use by=.EACHI? it adds SQL's GROUP BY to your query. If you are grouping then it is reasonable to have an aggregate functions, in case of grouping on join it is mandatory to provide j, even when doing it for equi-join.
Note the year=x.year in j argument, the rationale for using x. explicitly is described in #1615, otherwise you would get year equal to the value to which it was joined in i data.table.
@jangorecki thanks a lot for the detailed observations. It seems the key is allow.cartesian. I think it could be useful to keep a cookbook for data.table strategies to replicate SQL queries.
One more interesting observation, the inequality join is faster than foverlaps.
require(GenomicRanges)
q.gr= GRanges(query$id, IRanges(query$range1, query$range2)) # 12.7s!!!s.gr= GRanges(subject$id, IRanges(subject$range1, subject$range2))
system.time(gr_ans<- findOverlaps(q.gr, s.gr, type="within"))
# 16.4s# note that we have not obtained the counts yet, just the overlaps# the fact that q.gr takes ~13s is quite suspicious (i.e., makes me think that it does # some preprocessing and therefore should be included in the total run time)
RSQLite
# Thanks @jangorecki
library(RSQLite)
conn= dbConnect(SQLite())
dbWriteTable(conn, "query", query)
dbWriteTable(conn, "subject", subject)
sql='SELECT subject.id, subject.range1, subject.range2, COUNT(*) AS n FROM query INNER JOIN subject ON query.id = subject.id AND query.range1 >= subject.range1 AND query.range2 <= subject.range2 GROUP BY subject.id, subject.range1, subject.range2;'
system.time(sql_ans<- dbGetQuery(conn, sql))
# 53.3s
foverlaps
system.time({
setkey(subject, id, range1, range2)
folaps_ans<- foverlaps(query, subject, type="within", nomatch=0L, which=TRUE)
})
# 12.9s# note that we have not obtained the counts yet, just the overlaps
Another non-equi joins comparison with RSQLite: (not an interval join)
sql='SELECT subject.id, subject.range1, COUNT(*) AS n FROM query INNER JOIN subject ON query.id = subject.id AND query.range1 >= subject.range1 GROUP BY subject.id, subject.range1;'
system.time(sql_ans<- dbGetQuery(conn, sql))
# 50.7s
changed the title [-]binary search extensions to `<`, `<=`, `>`, `>=` and `!=`[/-][+]binary search extensions to `<`, `<=`, `>`, `>=`[/+]on Jul 5, 2016
Activity
arunsrinivasan commentedon Mar 29, 2016
Update posts:
http://stackoverflow.com/q/36284173/559784
http://stackoverflow.com/q/36207861/559784
http://stackoverflow.com/q/36190921/559784
http://stackoverflow.com/q/36533139/2490497
http://stackoverflow.com/q/37163070/559784
ywhcuhk commentedon Apr 1, 2016
This would be awesome if implemented !
non-equi joins update to NEWS. #1452.
Merge branch 'non-equi-joins'
mult="first"/"last" moved to bmerge.c, handles non-equi joins too, #1452
MichaelChirico commentedon Apr 10, 2016
Any plans to support syntax like
on = .(x == y, a < b +3)?arunsrinivasan commentedon Apr 10, 2016
Very likely not in this release (depends on how fast I wrap up the rest), but definitely useful. Perhaps as a new issue would be great.
MichaelChirico commentedon Apr 10, 2016
Done, see #1639
eantonya commentedon May 18, 2016
@arunsrinivasan can you give a quick example of
.EACHIfailing in combination with a non-equi join?arunsrinivasan commentedon May 18, 2016
Here's an example where it'll fail:
The idea for non-equi joins is to split data.table
x(here,dt) into groups where rows of all columns, independently, have values always in increasing order. Here, there'll be more than one such "group". In the examples you've worked so far, there must have been only one such group. If this is hard to follow, please wait a while. I'll have better explanations (with visualisations) for UseR'16 soon.eantonya commentedon May 18, 2016
Ok, thanks, so failure is actually catastrophic and not silent. That's good - I thought it just works incorrectly for some cases and was looking for an incorrect result.
Iirc the cases I've worked with all had a single column on LHS, which always satisfies the single group condition.
3 remaining items
ywhcuhk commentedon Jun 25, 2016
great work!!
Minor bug fix and code clean up, #1452
ywhcuhk commentedon Jun 28, 2016
It seems that for this to work, one has to specify
j.Here is a small example
what I want to get can be accomplished by
foverlaps:But I thought I could simply do this:
However, I got an error:
Why do I have to specify
j? All I wanted is to do a simply inequality join like in SQL.jangorecki commentedon Jun 28, 2016
@ywhuofu if you want inequality join like in SQL then why you use
by=.EACHI? it adds SQL's GROUP BY to your query. If you are grouping then it is reasonable to have an aggregate functions, in case of grouping on join it is mandatory to providej, even when doing it for equi-join.ywhcuhk commentedon Jun 28, 2016
@jangorecki thanks for you response. So now I am a little confused. Based on my example, what should I do instead?
jangorecki commentedon Jun 28, 2016
@ywhuofu Use
set.seedwhen dealing withrnorm. I've changedyear-5toyear-5Lin your code to keep it as integer.Note the
year=x.yearinjargument, the rationale for usingx.explicitly is described in #1615, otherwise you would getyearequal to the value to which it was joined inidata.table.ywhcuhk commentedon Jun 28, 2016
@jangorecki thanks a lot for the detailed observations. It seems the key is
allow.cartesian. I think it could be useful to keep a cookbook fordata.tablestrategies to replicate SQL queries.One more interesting observation, the inequality join is faster than
foverlaps.Handle nomatch=0L correctly for non-equi when by=.EACHI, #1452.
arunsrinivasan commentedon Jun 30, 2016
Benchmark:
TODO: add
MonetDBLitebenchmark later.Data:
Non-equi joins:
findOverlaps
RSQLite
foverlaps
system.time({ setkey(subject, id, range1, range2) folaps_ans <- foverlaps(query, subject, type="within", nomatch=0L, which=TRUE) }) # 12.9s # note that we have not obtained the counts yet, just the overlapsAnother non-equi joins comparison with
RSQLite: (not an interval join)non-equi joins
RSQLite
minor: verbose msg on timings/groups generated for nqjoins, #1452.
[-]binary search extensions to `<`, `<=`, `>`, `>=` and `!=`[/-][+]binary search extensions to `<`, `<=`, `>`, `>=`[/+]Better nestedid generation for nqjoins, better performance, better ve…
non-equi joins update to NEWS. Rdatatable#1452.
mult="first"/"last" moved to bmerge.c, handles non-equi joins too, Rd…