在单个表格中,我需要找到那些特定值相差最大给定量的对。例如,给定下表和最大差异0.5
:
val
---
1
1.2
1.3
4
4.5
6
期望的结果是:
val1 | val2
-----+-----
1 | 1.2
1 | 1.3
1.2 | 1.3
4 | 4.5
主要问题是我的桌子很大,并且在合理的时间内无法交叉产品。即不工作:
SELECT t1.val, t2.val
FROM table t1, table t2
WHERE abs(t1.val - t2.val) <= 0.5
有办法做到这一点吗?我读了window functions,所以至少我知道可以为每个条目计算上一个条目的值差异,获得上面的例子:
val | diff
----+-----
1 | 0
1.2 | 0.2
1.3 | 0.1
4 | 2.7
4.5 | 0.5
6 | 1.5
从这里开始,我需要找到diff
之和不超过给定最大值的范围。这可能吗?有更合理的方法吗?
我正在使用火花。
谢谢。
编辑:正如所指出的,我的查询还包括对称对以及值相等的es对。抱歉模棱两可。
然而,这不是重点。我的问题是加入。对于笛卡尔积,数据集太大。我正在寻找一种避免使用它的解决方案。
此外,我正在处理的数据集的大小是1000000元组。我不是 确定预期的执行时间,但有人建议必须有一个解决方案,避免在数据上使用笛卡尔积。
谢谢。
答案 0 :(得分:1)
你尝试的是关闭的。只需进行一些修改:
<div id="left-nav">
<ul>
<li><a class="left-nav-link" href="#first-link">First Link</a></li>
<li><a class="left-nav-link" href="#second-link">Second Link</a></li>
<li><a class="left-nav-link" href="#third-link">Third Link</a></li>
</ul>
</div>
答案 1 :(得分:1)
您可以生成基于时间的虚拟窗口:
import org.apache.spark.sql.functions._
import spark.implicits._ // Where spark is an instance of SparkSession
val df = Seq(1.0, 1.2, 1.3, 4.0, 4.5, 6).toDF("val")
val w = window(
$"val".cast("timestamp"), "1000 milliseconds", "500 milliseconds"
).cast("struct<start:double,start:double>").alias("window")
val windowed = df.select(w, $"val")
加入并过滤和删除重复项:
val result = windowed.alias("left")
.join(windowed.alias("right"), "window")
.where(abs($"left.val" - $"right.val") <= 0.5 && $"left.val" < $"right.val")
.drop("window").distinct
结果:
result.show
// +---+---+
// |val|val|
// +---+---+
// |1.0|1.2|
// |1.2|1.3|
// |4.0|4.5|
// |1.0|1.3|
// +---+---+
答案 2 :(得分:0)
我建议做的一件事是添加bucket
列,以便每个可能匹配的元组必须位于同一个存储桶或相邻的存储桶中。因此,我可以基于桶加入(equijoin)表自身,并从条件确实成立的结果中提取元组。我不确定它是否是一个好的解决方案,我还没有能够验证它。
/* max difference cannot span more than 2 buckets */
spark.sql("set max_diff=0.001")
var dec_count = 3
var bucket_size = scala.math.pow(10,-1 * dec_count)
var songs_buckets = songs.orderBy(col("artist_familiarity")).withColumn("bucket", round(col("artist_familiarity"), dec_count))
/*
tuples in adjacent buckets can have very close `artist_familiarity`.
add id to avoid duplicate pairs or tuples paired with themselves.
*/
songs_buckets = songs_buckets.withColumn("bucket2", $"bucket" - bucket_size).withColumn("id", monotonically_increasing_id())
songs_buckets.createOrReplaceTempView("songs_buckets")
var tmp = sql("SELECT s1.title as t1, s2.title as t2, s1.artist_familiarity as f1, s2.artist_familiarity as f2, s1.id as id1, s2.id as id2 FROM songs_buckets s1 JOIN songs_buckets s2 ON s1.bucket = s2.bucket OR s1.bucket = s2.bucket2")
tmp.createOrReplaceTempView("tmp")
var result = sql("SELECT t1, t2 FROM tmp WHERE id1 < id2 and f2 - f1 <= ${max_diff}")
result.show()
我还没有打算将变量名称更改回问题中的示例。它在大约12秒后显示结果的前20行。不确定这是否与延迟加载有关,因为它不会显示结果的count
,但它是我能做的最好的事情。