
在数据分析和处理中,我们经常需要根据非字母顺序或数值大小的自定义规则对数据进行排序。例如,将字符串"number"、"time"、"date"按照"number" -> "time" -> "date"的特定优先级进行排列,而不是默认的字典序。虽然许多编程语言(如javascript)提供了直接传入比较函数(comparisonfunction(val1, val2))来处理这类需求,但在bigquery的标准sql中,order by子句通常直接作用于列值或表达式的结果,并不直接支持这种“比较函数”的签名。
尽管BigQuery不直接支持将比较函数作为ORDER BY参数,但可以通过以下标准方法高效实现自定义排序。
对于大多数自定义排序场景,将需要排序的列值映射到一个可排序的数值或字符串,然后依据这个映射值进行排序,是最推荐且性能最优的方法。这种方法利用了BigQuery的并行处理能力,能够很好地扩展到大规模数据集。
示例:
假设我们有如下数据:
| val |
|---|
| date |
| time |
| number |
我们希望按照 "number" (1) -> "time" (2) -> "date" (3) 的顺序进行排序。
WITH tbl AS (
SELECT "date" val UNION ALL
SELECT "time" UNION ALL
SELECT "number"
)
SELECT
tbl.val,
CASE tbl.val
WHEN 'number' THEN 1
WHEN 'time' THEN 2
WHEN 'date' THEN 3
ELSE 999 -- 处理未定义的其他值
END AS custom_rank
FROM tbl
ORDER BY custom_rank;输出:
| val | custom_rank |
|---|---|
| number | 1 |
| time | 2 |
| date | 3 |
优点:
BigQuery引入了排序规则(collations)来支持对字符串进行更精细的排序,例如区分大小写、重音或特定语言的排序规则。虽然这允许在一定程度上自定义字符串排序行为,但它主要针对语言和区域设置相关的排序,目前尚不支持完全任意的、基于用户自定义逻辑的比较函数。
示例(概念性):
SELECT my_string_column FROM my_table ORDER BY my_string_column COLLATE 'en_US:ci'; -- 忽略大小写进行排序
注意事项:
对于非常特定且复杂的排序逻辑,尤其是在数据量相对较小(数百行以内)的情况下,可以考虑使用JavaScript用户定义函数(UDF)。这种方法能够模拟JavaScript中sort(comparisonFunction)的行为。
核心思想: 由于ORDER BY不能直接接受比较函数,我们不能直接在ORDER BY子句中使用UDF来比较两个值。相反,这种方法的工作原理是:
示例:
沿用之前的需求,我们希望通过JavaScript UDF实现 "number" -> "time" -> "date" 的排序。
-- 定义一个JavaScript UDF,用于对字符串数组进行自定义排序
CREATE TEMP FUNCTION sortme(MyValues ARRAY<STRING>)
RETURNS ARRAY<STRING>
LANGUAGE js AS
"""
// 定义自定义的排序映射
const RANK_MAP = {"number": 1, "time": 2, "date": 3};
// 定义比较函数
function customComparisonFunction(val1, val2) {
// 如果值不在RANK_MAP中,可以给一个默认的优先级,例如:
const rank1 = RANK_MAP[val1] !== undefined ? RANK_MAP[val1] : 999;
const rank2 = RANK_MAP[val2] !== undefined ? RANK_MAP[val2] : 999;
return rank1 - rank2;
}
// 使用自定义比较函数对数组进行排序
MyValues.sort(customComparisonFunction);
return MyValues;
""";
-- 原始数据
WITH tbl AS (
SELECT "date" AS val UNION ALL
SELECT "time" UNION ALL
SELECT "number" UNION ALL
SELECT "unknown_value" -- 包含一个未在RANK_MAP中定义的值
),
-- 使用UDF对所有不重复的val进行排序
helper AS (
SELECT sortme(ARRAY_AGG(DISTINCT val)) AS sorted_values_array FROM tbl
)
-- 将原始表与排序后的数组连接,并根据偏移量排序
SELECT
t.val
FROM tbl AS t
LEFT JOIN (
SELECT
val,
sort_by -- 排序后的索引
FROM helper,
UNNEST(helper.sorted_values_array) AS val WITH OFFSET sort_by
) AS sorted_map
ON t.val = sorted_map.val
ORDER BY sorted_map.sort_by;输出:
| val |
|---|
| number |
| time |
| date |
| unknown_value |
性能考量与注意事项:
在BigQuery中实现自定义排序时,应根据具体需求和数据规模选择最合适的方法:
通过理解这些不同的策略及其优缺点,开发者可以在BigQuery中有效地实现各种自定义排序需求。
以上就是BigQuery中的自定义排序:策略与实现的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号