首页 > 数据库 >Spark SQL 抽样函数 ——TABLESAMPLE 的坑点

Spark SQL 抽样函数 ——TABLESAMPLE 的坑点

时间:2024-04-21 23:48:03浏览次数:23  
标签:TABLESAMPLE 坑点 ctx number Sample fraction SQL table

最近需要实现一段 Spark SQL 逻辑,对数据集进行抽样指定的行数。

由于数据集较大,刚开始的逻辑是,取窗口函数随机排序后 row_number 的前 n 行。但运行速度较慢,所以想起了 TABLESAMLE 函数,支持直接取 Rows, 尝试后发现速度特别快,基本上几秒内就完成对亿级数据的采样。所以好奇就去查看文档和代码逻辑。

The TABLESAMPLE statement is used to sample the table. It supports the following sampling methods:

  • TABLESAMPLE(x ROWS): Sample the table down to the given number of rows.
  • TABLESAMPLE(x PERCENT): Sample the table down to the given percentage. Note that percentages are defined as a number between 0 and 100.
  • TABLESAMPLE(BUCKET x OUT OF y): Sample the table down to a x out of y fraction.

Note: TABLESAMPLE returns the approximate number of rows or fraction requested.

文档中没有对实现逻辑有过多的说明,所以去代码中找问题。

源码中,匹配 SampleByRowsContext 时,调用的方法是 Limit(expression(ctx.expression), query),也就是说和 limit rows 是一个逻辑。

而 SampleByPercentileContext 实现的才是随机采样。

所以,如果对抽样的随机性有要求,还是老老实实用 SampleByPercentileContext,或者窗口函数。

附 相关代码:

  /**
   * Add a [[Sample]] to a logical plan.
   *
   * This currently supports the following sampling methods:
   * - TABLESAMPLE(x ROWS): Sample the table down to the given number of rows.
   * - TABLESAMPLE(x PERCENT) [REPEATABLE (y)]: Sample the table down to the given percentage with
   * seed 'y'. Note that percentages are defined as a number between 0 and 100.
   * - TABLESAMPLE(BUCKET x OUT OF y) [REPEATABLE (z)]: Sample the table down to a 'x' divided by
   * 'y' fraction with seed 'z'.
   */
  private def withSample(ctx: SampleContext, query: LogicalPlan): LogicalPlan = withOrigin(ctx) {
    // Create a sampled plan if we need one.
    def sample(fraction: Double, seed: Long): Sample = {
      // The range of fraction accepted by Sample is [0, 1]. Because Hive's block sampling
      // function takes X PERCENT as the input and the range of X is [0, 100], we need to
      // adjust the fraction.
      val eps = RandomSampler.roundingEpsilon
      validate(fraction >= 0.0 - eps && fraction <= 1.0 + eps,
        s"Sampling fraction ($fraction) must be on interval [0, 1]",
        ctx)
      Sample(0.0, fraction, withReplacement = false, seed, query)
    }

    if (ctx.sampleMethod() == null) {
      throw QueryParsingErrors.emptyInputForTableSampleError(ctx)
    }

    val seed = if (ctx.seed != null) {
      ctx.seed.getText.toLong
    } else {
      (math.random() * 1000).toLong
    }

    ctx.sampleMethod() match {
      case ctx: SampleByRowsContext =>
        Limit(expression(ctx.expression), query)

      case ctx: SampleByPercentileContext =>
        val fraction = ctx.percentage.getText.toDouble
        val sign = if (ctx.negativeSign == null) 1 else -1
        sample(sign * fraction / 100.0d, seed)

      case ctx: SampleByBytesContext =>
        val bytesStr = ctx.bytes.getText
        if (bytesStr.matches("[0-9]+[bBkKmMgG]")) {
          throw QueryParsingErrors.tableSampleByBytesUnsupportedError("byteLengthLiteral", ctx)
        } else {
          throw QueryParsingErrors.invalidByteLengthLiteralError(bytesStr, ctx)
        }

      case ctx: SampleByBucketContext if ctx.ON() != null =>
        if (ctx.identifier != null) {
          throw QueryParsingErrors.tableSampleByBytesUnsupportedError(
            "BUCKET x OUT OF y ON colname", ctx)
        } else {
          throw QueryParsingErrors.tableSampleByBytesUnsupportedError(
            "BUCKET x OUT OF y ON function", ctx)
        }

      case ctx: SampleByBucketContext =>
        sample(ctx.numerator.getText.toDouble / ctx.denominator.getText.toDouble, seed)
    }
  }

标签:TABLESAMPLE,坑点,ctx,number,Sample,fraction,SQL,table
From: https://www.cnblogs.com/aka-chestnut/p/18149765

相关文章

  • SQL Server 解决不区分中英文大小写方法
     区分大小写、全半角字符的方法1.查大写字母.区分全角半角select*from表where列名collateChinese_PRC_CS_AS_WSlike'%A%' (就是在列名后加collateChinese_PRC_CS_AS_WS) 1.查大写字母.不区分全角半角collateChinese_PRC_CS_AS2.查全角.区分大小写collateChi......
  • MySQL-06.索引的数据结构
    1.为什么使用索引索引是存储引擎用于快速找到数据记录的一种数据结构,就好比一本书的目录部分,通过目录中找到对应文章的页码,便可快速定位到需要的文章。MySQL中的索引也是一样的道理,进行数据查找时,首先查看查询条件是否命中某条索引,符合则通过索引查找相关数据,如果不符合则需要全......
  • MySql入门操作 3.0
    子查询:在查询列中设定特定信息,筛选要的特殊信息: 标量子查询:在内部的select中设定具体常量,通过常量进行筛选对应的列;具体格式不太好描述,如果对于上一章所使用的指令可以熟练应用那么这里应该也没啥问题,就是一个嵌套类比罢了下面直接给示例:相当于在要设定的条件中再使用一......
  • MAC配置mysql:mac下启动/停止/重启mysql服务
    Mac安装msyql 第一种就是直接brew installmysql第二种就是下载安装咯:https://dev.mysql.com/downloads/mysql/配置mysql系统环境变量vim  .bash_profile增加 exportPATH=${PATH}:/usr/local/mysql/binsource.bash_profile  回车执行,运行环境变量。再输入m......
  • [转帖]MySQL知识体系的三驾马车
    https://plantegg.github.io/2019/05/26/MySQL%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB%E7%9A%84%E4%B8%89%E9%A9%BE%E9%A9%AC%E8%BD%A6/ MySQL知识体系的三驾马车在我看来要掌握好MySQL的话要理解好这三个东西:索引(B+树)日志(WAL)事务(可见性)索引决定了查询的性能,也是用......
  • MySQL的安装与配置——详细教程
    转载自:Winton-H原文链接免安装版的MysqlMySQL关是一种关系数据库管理系统,所使用的SQL语言是用于访问数据库的最常用的标准化语言,其特点为体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,在Web应用方面MySQL是最好的RDBMS(RelationalDatabaseManagementSys......
  • django sql 操作
    *非空判断ifparamisNone://只判断null值ifnotparam://判断null值同时判断字段是否空值*if-elseif-else写法:ifself.returned_at: return"已還書"elifself.overdue_settled: return"借閱中(已繳部分金額)"else: return"借閱中(已繳部......
  • sql server 的一些功能
    1 添加 applicationname  结果 2 /******SSMS的SelectTopNRows命令的脚本******/setstatisticstimeonsetstatisticsioonSELECTTOP(1000)[ID],[CreateTime],[ProductID],[Count]FROM[Order].[dbo].[Orders]  ......
  • MySQL安装部署
    1.查看是否已经安装Mysqlrpm-qa|grepmysql如果你查看出来有东西,可以使用下面命令将其删除(xxx为文件全名)rpm-exxx例如:rpm-qa|grepmariadb#mariadb-libs-5.5.68-1.el7.x86_64rpm-e--nodepsmariadb-libs-5.5.68-1.el7.x86_642.下载官方Mysql包1.......
  • SQLITE
    SQLITE1.简介1>DDL-数据定义语言命令描述CREATE创建一个新的表,一个表的视图,或者数据库中的其他对象。ALTER修改数据库中的某个已有的数据库对象,比如一个表。DROP删除整个表,或者表的视图,或者数据库中的其他对象。2>DML-数据操作语言命令描述INSER......