Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

Apache Drill学习笔记

8
Aug
2017

Apache Drill学习笔记

By Alex
/ in BigData,Database
/ tags MongoDB, 学习笔记
0 Comments
简介

Apache Drill是一个模式自由(Schema-free )的、低延迟的、分布式的、可扩容的SQL查询引擎,可以让你使用熟悉的SQL语法对各种非关系型数据库进行操作。Drill支持针对PB级别数据的即席查询。Drill支持大量NoSQL数据和文件系统,包括MongoDB、HBase、HDFS。支持对不同数据源中的数据进行join操作。Drill支持Windows/Linux/Mac系统,可以很容易的在服务器集群中扩容。

Drill的优势包括:

  1. 支持模式自由的JSON模型,Drill是第一个、目前也是唯一的不对Schema做任何要求的分布式SQL引擎。这种模式自由类似于MongoDB。Drill在查询执行过程中可以自动发现Schema
  2. 即席的查询复杂的、半结构化的数据。你不需要对数据进行任何转换,Drill对SQL进行了直观的扩展,方面处理内嵌数据,就好像内嵌数据是普通的SQL列一样
  3. 真实的SQL语言,Drill支持标准的SQL 2003语法。支持DATE, INTERVAL, TIMESTAMP, VARCHAR等数据类型,以及关联子查询、JOIN子句
  4. 方便的和既有BI工具集成
  5. 针对Hive表的交互式查询
  6. 同时访问多个数据源
  7. 用户自定义函数支持,直接支持Hive用户定义函数
  8. 高性能、可扩容
基本概念
Drillbit

Drill的核心是Drillbit服务,它负责接受客户请求、处理查询、返回查询结果。Drillbit可以被安装到并运行在数据库集群的所有节点上,这样在执行查询时可以减少网络流量。Drill通过ZooKeeper来维护集群成员状态、检查健康状况。

当你以SQL的形式发起一个查询时,查询被发送给Drill集群中的一个Drillbit,这个Drillbit成为领头(Foreman),它负责协作其它Drillbit以完成查询执行:

  1. 解析SQL语句,将SQL操作符转换为Drill理解的逻辑操作符。这些逻辑操作符共同组成了逻辑执行计划,描述了生成查询结果所需的操作、哪些数据源需要参与其中
  2. Foreman把逻辑计划发送给基于成本的优化器,优化操作符的顺序,最终转换为物理执行计划
  3. Foreman中的并行器(parallelizer)把物理计划分为多个阶段 —— major/minor fragments。这些片断会并行的在所配置的数据源中执行
Major Fragments

构成执行计划的一个阶段,每个阶段可以由1-N个主片断构成,这些片断代表完成此阶段Drill必须执行的操作。Drill为每个主片段分配一个ID。

例如,为了针对两个文件进行哈希聚合,Drill可能创建具有两个阶段的查询计划,每个计划包含一个主片断。第一个阶段专注于扫描文件,第二个阶段则专注于数据的聚合。

Drill使用exchange operator来分隔多个主片段,所谓exchange可以是:

  1. 数据位置的变化,或/和
  2. 物理计划的并行化

一个exchange由sender/receiver组成,允许数据在节点之间流动。

主片断本身不负责任何查询任务的实际执行。每个主片段包含若干个从片断,从片断负责执行并完成查询。

你可以获得物理计划的JSON表示,修改之,然后通过Drill的SUBMIT PLAN命令提交执行。

Minor Fragments

每个主片断被并行化为多个从片断。从片断是运行在一个线程内的逻辑工作单元(也叫slice)。每个从片断被分配一个ID。

Foreman中的并行器在执行期间把一个主片段拆分为1-N个从片断。Drill会根据数据局部性(data locality)把从片断调度到特定的节点上,并尽快的执行从片断(根据上流数据需求)。

从片断包含1-N个关系操作符,关系操作符执行关系型操作,例如scan, filter, join,group by。

从片断们可以形成树形结构,并分为root、intermediate、leaf三种角色。这种执行树仅仅包含一个运行在Foreman上的root从片断,需要执行的操作逐级下发,直到leaf从节点。leaf从节点与存储层交互或者访问磁盘数据,得到部分的结果,由上级节点进行聚合操作。 

核心模块

每个Drillbit都由以下模块组成:

drillbitmodules

RPC endpoint

Drill暴露的低资源消耗的RPC协议,用于客户端连接。客户端可以直接连接到Drillbit,或者通过ZooKeeper连接。推荐使用后一种方式,以隔离Drill集群变化造成的影响。

SQL parser

基于开源SQL解析器Calcite实现,用于解析客户端请求。解析结果是语言无关、计算机友好的逻辑计划。

Storage plugin interface

屏蔽特定数据存储的差异性。存储插件的功能包括:

  1. 从数据源获取元数据
  2. 读写数据
  3. 数据位置感知、一系列优化规则
客户端

访问Drill的途径包括:

  1. Drill Shell
  2. Drill Web Console
  3. ODBC/JDBC
  4. C++ API
安装
嵌入式安装

如果仅仅在单个节点上使用Drill,可以使用嵌入式安装。这种模式下,不需要安装ZooKeeper,也不需要进行配置。当你启动Drill shell时,本地的Drillbit服务自动启动。

安装步骤:

Shell
1
2
wget http://apache.mirrors.hoobly.com/drill/drill-1.11.0/apache-drill-1.11.0.tar.gz
tar xzf apache-drill.tar.gz

要运行Drill,执行下面的命令以打开Drill Shell:

Shell
1
2
3
4
5
6
drill-embedded
0: jdbc:drill:zk=local>
# 命令提示符说明:
# 0 表示连接到drill的连接数
# jdbc为连接类型
# zk=local 作为ZooKeeper的代替

或者执行 sqlline -u "jdbc:drill:zk=local"

要退出Drill Shell,在Shell中输入 !quit

要访问Web Console,在浏览器地址栏输入 http://127.0.0.1:8047/

分布式安装

要在Hadoop集群环境下使用Drill,可以使用分布式安装。ZooKeeper的分布式集群是必须的前提,你也需要对Drill进行配置,才能连接到各种数据源。

下载、解压后,修改配置文件:

conf/drill-override.conf
Shell
1
2
3
4
5
6
drill.exec: {
  # Drill集群标识符
  cluster-id: "drillbits",
  # ZooKeeper连接字符串
  zk.connect: "172.21.0.1:2181,172.21.0.2:2181,172.21.0.3:2181"
}

要以集群模式启动Drill,首先需要在集群的每个节点上启动守护程序Drillbit:

Shell
1
2
# 命令格式:drillbit.sh [--config <conf-dir>] (start|stop|status|restart|autorestart)
/home/alex/JavaEE/middleware/drill/bin/drillbit.sh --config /home/alex/JavaEE/middleware/drill/conf start

要连接到分布式部署的Drill Shell,可以:

  1. 执行drill-conf,此脚本使用conf/drill-override.conf配置
  2. 执行drill-localhost连接到运行在本机的ZooKeeper 

连接上以后,可以执行 SELECT * FROM sys.drillbits;查询Drill集群成员信息。

在Docker中运行

参考如下Dockerfile:

Dockerfile
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM openjdk:8-jre
 
ENV CLUSTER_ID drillbits
ENV ZK_CONNECT 172.21.0.1:2181
 
 
RUN apt-get install -y wget tar
 
ADD docker-entrypoint.sh .
ADD apache-drill.tar.gz  .
 
RUN chmod +x docker-entrypoint.sh && mv apache-drill-1.11.0 /opt/drill
 
ENTRYPOINT ["/docker-entrypoint.sh"]

入口脚本:

docker-entrypoint.sh
Shell
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env bash
 
cat << EOF  > /opt/drill/conf/drill-override.conf
drill.exec: {
  cluster-id: "$CLUSTER_ID",
  zk.connect: "$ZK_CONNECT"
}
EOF
 
/opt/drill/bin/drillbit.sh --config /opt/drill/conf run

创建并运行容器: 

Shell
1
2
docker run -e ZK_CONNECT=172.21.0.1:2181,172.21.0.2:2181,172.21.0.3:2181 --name drill-14 \
           --network local --ip 172.21.1.14 -d docker.gmem.cc/drill 
配置
内存配置

你可以配置分配给Drillbit的用于处理查询的直接内存的量。默认配置是8G,在高负载下可能需要16G或者更多。

Drill使用Java的直接内存来存储执行中的操作,除非必须,它不会使用磁盘。这和MapReduce不同,后者将任务每个阶段的输出都存放在磁盘上。JVM的堆内存不限制Drillbit能够使用的直接内存。Drillbit的堆内存通常设置到4-8G就足够了,因为Drill避免在堆中写数据。

从1.5版本开始,Drill使用新的直接内存分配器,可以更好的使用、跟踪直接内存。由于这一变化,sort操作符可能因为内存不足而失败。

系统选项 planner.memory.max_query_memory_per_node 设置单个Drillbit中每个查询的sort操作符能够使用的内存量。如果一个查询计划中包含多个sort操作符,它们共享这一内存。如果sort查询出现内存问题,考虑增加此选项的值。如果问题仍然存在,考虑减小系统选项planner.width.max_per_node的值,该值控制单个节点的并行度。

修改内存限制

在drill-env.sh中设置环境变量:

drill-env.sh
Shell
1
2
3
4
# 如果堆内存没有设置,将其设置为4G
export DRILL_HEAP=${DRILL_HEAP:-"4G”}  
# 如果直接内存没有设置,将其设置为8G
export DRILL_MAX_DIRECT_MEMORY=${DRILL_MAX_DIRECT_MEMORY:-"8G"}
安全配置
角色

Drill提供两种角色:

角色 说明
USER 可以对具有访问权限的数据执行查询。每个存储插件负责读写权限的管理
ADMIN

当启用身份验证时,仅仅具有Drill集群管理员角色的用户能够执行以下任务:

  1. 使用ALTER SYSTEM来改变系统级选项
  2. 通过Web Console或者REST API来更新存储插件配置
  3. 提供和普通用户不同的导航栏
  4. 查看集群中正在运行的所有查询的profiles
  5. 取消运行中的查询
身份模拟

用户身份模拟(Impersonation)允许一个服务代表客户端执行某个操作。默认的,身份模拟被关闭。

PAM认证

Drill支持基于Linux PAM的身份验证。PAM允许和系统密码文件(/etc/passwd)或者LDAP等PAM实体进行交互以完成身份验证。

使用PAM验证时,运行Drill查询的用户必须存在于每一个Drill节点上。

Kerberos认证

Drill支持Kerberos v5网络认证、客户端 - Drill的通信加密。需要配合JDBC驱动来使用该认证方式。

在启动时,一个Drillbit必须被验证。在运行时Drill使用和KDC共享的keytab文件,Drill使用该文件来验证票据的合法性。

配置 security.user.encryption.sasl.enabled参数为true,可以启用Kerberos加密 —— 保证客户端到Drillbit的数据安全。

你需要为Drill创建principal,可以:

Shell
1
2
3
4
kadmin
# 一个集群使用单个实体
# addprinc  <username>/<clustername>@<REALM>.COM
addprinc  drill/drillbits@GMEM.CC

你需要为上面的principal创建一个keytab文件:

Shell
1
ktadd -k /home/alex/JavaEE/middleware/drill/conf/drill.keytab drill/drillbits@GMEM.CC

然后,为Drill配置文件添加:

Shell
1
2
3
4
5
6
7
8
9
drill.exec: {
  security: {
      user.auth.enabled: true,
      user.encryption.sasl.enabled: true,
      auth.mechanisms: ["KERBEROS"],
      auth.principal: "drill/drillbits@GMEM.CC",
      auth.keytab: "/home/alex/JavaEE/middleware/drill/conf/drill.keytab"
  }
}

并重启。

配置选项
关键启动选项

你可以在conf/drill-override.conf中配置启动选项,其中最常用的如下表:

选项 说明
drill.exec.http.ssl_enabled 布尔(TRUE|FALSE),默认FALSE。是否启用HTTPS支持
drill.exec.sys.store.provider.class 设置持久化存储提供者(PStore),PStore保存配置数据、Profile
drill.exec.buffer.size 缓冲区大小,增加此配置可以加快查询速度
drill.exec.sort.external.spill.directories 进行Spool操作时使用的目录
drill.exec.zk.connect 提供ZooKeeper连接字符串
drill.exec.profiles.store.inmemory 布尔,默认FALSE。是否在内存中存放查询Profiles
drill.exec.profiles.store.capacity 上个选项取值TRUE时,内存中最多存放的查询Profiles数量
存储插件

Drill通过存储插件(Storage)连接到底层数据源。存储插件通常负责:

  1. 连接到数据源,例如数据库、文件
  2. 优化Drill查询的执行
  3. 提供数据的位置信息
  4. 配置工作区、文件格式以读取数据

常用的几个存储插件跟随Drill一起安装

注册插件配置

所谓插件配置,就是连接到目标数据源的配置信息。Drill默认注册了这几个默认的插件配置:

插件配置 说明
cp 指向Drill类路径中的JAR文件,你可以对其中的文件进行查询
dfs 指向本地文件系统。你可以使用对应的存储引擎配置指向任意分布式系统,例如Hadoop 
hbase 提供到HBase的连接 
hive 将Drill和Hive的元数据抽象(文件、HBase)机制集成
mongo 提供到MongoDB的连接 
注册MongoDB配置

通过Web Console连接(地址示例:http://172.21.1.14:8047/storage),可以注册插件配置。

点击Disable按钮可以禁用当前的配置,禁用后,show databases中对应的条目消失。点击Enable可以启用某个可用配置。输入存储插件名称,点击Create,可以建立新的插件配置。

插件配置都是JSON格式,MongoDB配置的示例:

JavaScript
1
2
3
4
5
{
  "type": "mongo",
  "connection": "mongodb://root:root@mongo-s1.gmem.cc:27017/",
  "enabled": true
}
测试配置正确性

打开drill-conf,输入命令验证连接是否正常:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0: jdbc:drill:> show databases;
+---------------------+
|     SCHEMA_NAME     |
+---------------------+
| INFORMATION_SCHEMA  |
| mongo.admin         |
| mongo.bais          |
| mongo.config        |
| sys                 |
+---------------------+
 
# 上面的结果意味着已经连接到此配置,注意数据库名称的前缀,就是配置的名称
 
use mongo.bais;
select regNo,stocks[0].stockName as stock0Name from corps;
+----------------+-------------+
|     regNo      | stock0Name  |
+----------------+-------------+
| 3208261000000  | 汪震          |
+----------------+-------------+
 
# 上面的结果意味着查询测试成功 
JDBC/ODBC

除了Shell、Web Console以外,Drill还提供C++ API以及JDBC、ODBC驱动。

JDBC

添加依赖以使用此驱动:

XML
1
2
3
4
5
<dependency>
    <groupId>org.apache.drill.exec</groupId>
    <artifactId>drill-jdbc</artifactId>
    <version>1.11.0</version>
</dependency>
URL格式
Shell
1
2
# jdbc:drill:zk={ZooKeeper连接字符串}/drill/{Drill集群标识符};schema={存储插件配置.数据库名称}
jdbc:drill:zk=zookeeper-1.gmem.cc:2181,zookeeper-2.gmem.cc:2181,zookeeper-3.gmem.cc:2181/drill/drillbits;schema=mongo.bais
JDBC代码示例
Java
1
2
3
4
5
6
7
8
Class.forName( "org.apache.drill.jdbc.Driver" );
String url = "jdbc:drill:zk=zookeeper-1.gmem.cc:2181/drill/drillbits;schema=mongo.bais";
Connection connection = DriverManager.getConnection( url );
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery( "select regNo,stocks[0].stockName as stock0Name from corps" );
while ( rs.next() ) {
    System.out.println( rs.getString( 2 ) );
}
查询数据
复杂数据结构

所谓复杂数据结构,是指与关系型数据库那种简单的表格形式(行、字段)不同的,具有复杂数据类型字段(内嵌结构)的数据结构。

Drill可以在执行查询请求的时候,发现数据的结构。类似于JSON、Parquet之类的嵌套数据结构不仅仅可以被简单的访问,Drill还提供特殊的操作符、函数对其进行钻取操作。这些操作符、函数能够:

  1. 引用内嵌数据结构的值
  2. 访问数组元素、嵌套数组
JOIN操作

你可以使用SQL标准的join子句来连接两个表或/和文件。示例:

SQL
1
select c.regNo, c.corpName, o.name from corps as c join orgs as o on c.belongOrg = o._id where c.regCapi > 10000;
访问嵌套数据
SQL
1
2
3
4
5
-- 访问内嵌文档
select c.address.detail as addr from corps as c;
-- 访问内嵌数组
select c.stocks[0].stockName from corps as c;
select c.stocks[0].stockName, c.stocks[0].subsCapi from corps as c;
日志与调试

Drill使用Logback作为默认的日志系统,日志配置位于conf/logback.xml。

默认的,日志被输出到文件系统,位于$DRILL_HOME/logs目录下,你可以在drill-env.sh中设置$DRILL_HOME环境变量。在每个Drill节点上,文件drillbit_queries.json记录每个查询的ID、profile信息。

性能优化
查询计划

要获得查询的执行计划,执行 explain plan for语句,示例:

SQL
1
explain plan for select regNo,corpName from bais.corps;

从输出结果中,可以看到Drill如何访问底层数据源:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# explain plan for select regNo,corpName from bais.corps where regNo like '3208%';
00-00    Screen
00-01      Project(regNo=[$0], corpName=[$1])
00-02        UnionExchange
01-01          Scan(groupscan=[MongoGroupScan [MongoScanSpec=MongoScanSpec
                   [dbName=bais, collectionName=corps, filters=null], columns=[`regNo`, `corpName`]]])
                                                       # 没有过滤器,意味着需要全表扫描
# explain plan for select regNo,corpName from bais.corps where regNo > '320800100' and regNo < '320800200' limit 10;
00-00    Screen
00-01      Project(regNo=[$0], corpName=[$1])
00-02        SelectionVectorRemover
00-03          Limit(fetch=[10])
00-04            UnionExchange
01-01              SelectionVectorRemover
01-02                Limit(fetch=[10])
01-03                  Scan(groupscan=[MongoGroupScan [MongoScanSpec=MongoScanSpec
                     [dbName=bais, collectionName=corps,
                     filters=Document{{$and=[Document{{regNo=Document{{$gt=320800100}}}},
                     Document{{regNo=Document{{$lt=320800200}}}}]}}], columns=[`regNo`, `corpName`]]])
                                                       # 这里可以看到使用了MongoDB的查询过滤,可能利用到索引
SQL参考

Drill支持ANSI标准SQL,你可以使用统一的语法查询各种数据源。为了支持嵌套数据结构,Drill提供特殊的操作符和函数。

数据类型
数据类型 说明
BIGINT 8字节有符号整数
BINARY 变长二进制字符串,示例:B@e6d9eb7
BOOLEAN 布尔值,示例:true
DATE YYYY-MM-DD格式的日期
DECIMAL(p,s)   DECIMAL(p,s)   NUMERIC(p,s) 38位精度数字
FLOAT 4字节浮点数
DOUBLE 8字节浮点数
INTEGER   INT 4字节有符号整数
INTERVAL 日/月时间间隔
SMALLINT 2字节有符号整数
TIME HH:mm:ss格式的日期
TIMESTAMP yyyy-MM-dd HH:mm:ss.SSS格式的时间戳
CHARACTER VARYING    CHARACTER    CHAR   VARCHAR UTF-8字符串
Map 键值对形式的容器,KVGEN、FLATTEN函数用于处理此类型
Array 数组形式的容器,FLATTEN函数用于处理此类型
类型转换

使用CAST、CONVERT TO/FROM、TO_CHAR、TO_DATE、TO_NUMBER、TO_TIMESTAMP,可以进行显式的类型转换。某些类型之间可以进行隐式转换,NULL可以转换到任何类型。示例代码:

SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- CAST (<expression> AS <data type>)
CAST( regNo as INT )
 
-- 把目标列转换为字节
CONVERT_TO (column, type)
-- 把regNo作为大端整数,转换为字节
CONVERT_TO(regNo , 'INT_BE')
 
-- 把字节转换为type
CONVERT_FROM(column, type)
-- 把字符串转换为JSON map
CONVERT_FROM('{x:100, y:215.6}' ,'JSON')
 
-- TO_CHAR (expression, 'format') 转换数字、日期、时间、时间戳为字符串形式
SELECT TO_CHAR(1256.789383, '#,###.###') FROM (VALUES(1));   -- 1,256.789
TO_CHAR((CAST('2008-2-23' AS DATE)), 'yyyy-MMM-dd')          -- 2008-Feb-23
TO_CHAR(CAST('12:20:30' AS TIME), 'HH mm ss'                 --  12 20 30
TO_CHAR(CAST('2015-2-23 12:00:00' AS TIMESTAMP), 'yyyy MMM dd HH:mm:ss')
                                                             -- 2015 Feb 23 12:00:00 
 
-- TO_DATE (expression [, 'format']) 转换字符串或者UNIX时间戳为日期
TO_DATE('2015-FEB-23', 'yyyy-MM-dd')
-- TO_TIME (expression [, 'format']) 转换为时间
TO_TIME('12:20:30', 'HH:mm:ss')
TO_TIME(82855000)
-- TO_TIMESTAMP (expression [, 'format'])
TO_TIMESTAMP('2008-2-23 12:00:00', 'yyyy-MM-dd HH:mm:ss')
SQL函数

主要分为数学、日期、字符串、聚合等函数,参考官方文档。

窗口函数

窗口函数针对一系列行进行计算操作,并为每一行返回单个值。这些值虽然归属到某个行,但是它可能取决于其它多个行(这些行就是所谓窗口)。

你可以使用 OVER()来定义一个窗口,此子句将窗口函数与其它的聚合类函数区分开来,一个查询可以使用多个窗口函数(对应一个或者多个窗口定义)。OVER()子句能够:

  1. 定义对行进行分组(partition)的标准,聚合函数在这些分组上进行。这通过PARTITION BY子句实现
  2. 在一个分组内部,对行进行排序。这通过ORDER BY子句实现

对于窗口函数,你需要注意:

  1. 仅仅支持在查询的SELECT、ORDER BY字句中使用窗口函数
  2. Drill在WHERE, GROUP BY, HAVING之后处理窗口函数
  3. 在聚合函数之后跟随OVER()导致其作为窗口函数使用
  4. 使用窗口函数,你可以针对窗口帧中任意数量的行进行聚合
  5. 如果要针对FLATTEN子句的生成的结果集执行窗口函数,应该在子查询中使用FLATTEN
语法

窗口函数完整的调用语法:

SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- window_function指定一种窗口函数,这些函数可能和普通的聚合函数同名,识别它是否为窗口函数的唯一方法就是看看
-- 后面有没有OVER关键字。窗口函数在窗口内部进行聚合
-- expression 为列表达式
-- PARTITION BY关键字定义了窗口:
-- expr_lists 可以是  expression | column_name [, 其它expr_list ]
-- ORDER BY 定义窗口内排序规则,如果没有PARTITION BY则针对整个表格排序
--  order_lists 可以是 expression | column_name [ASC | DESC] [ NULLS { FIRST | LAST } ] [, 其它 order_list ]  
-- frame_clause 可以是:
-- { RANGE | ROWS } frame_start
-- { RANGE | ROWS } BETWEEN frame_start AND frame_end
-- frame_start 格式:UNBOUNDED PRECEDING 或者 CURRENT ROW
-- frame_end 格式:CURRENT ROW 或者 UNBOUNDED FOLLOWING
window_function (expression) OVER (
    [ PARTITION BY expr_list ]
    [ ORDER BY order_list ][ frame_clause ] )  
分类
窗口函数分类 说明
聚合 AVG() 计算平均值、COUNT()计算总数、MAX()计算最大值、MIN()计算最小值、SUM()求和
排名 返回当前行在分组中的排名:
  1. CUME_DIST() 返回相对排名:(高名次行数 + 同名次行数) / 总行数
  2. DENSE_RANK() 根据窗口的ORDER BY表达式进行排序,排序号不存在gap,也就是说同名次(peer)不会导致后续名次跳号
  3. NTILE() 尽可能的把窗口分组中的所有行划分到指定数量的排名组中
  4. PERCENT_RANK(),百分比排名:(当前行数 - 1) / (分组总行数 - 1)
  5. RANK(),类似于第2个,但是允许gap存在,也就是说两行并列的第1名之后的名次是3
  6. ROW_NUMBER(),返回行号,取决于ORDER BY表达式
值
  1. LAG(),返回分组中上一行的某个列(或者表达式)的值,如果没有上一行,返回NULL
  2. LEAD(),返回分组中下一行的某个列(或者表达式)的值,如果没有下一行,返回NULL
  3. FIRST_VALUE(),返回窗口中第一行的值
  4. LAST_VALUE(),返回窗口中最后一行的值
示例
SQL
1
2
3
4
5
-- 查询企业信息,为结果集的每一行增加列:当前企业类型的平均注册资金
select
    cast(c.corpName as char) corpName, c.corpType,
    avg( c.regCapi ) over( partition by c.corpType) as avgRegCapi  
from bais.corps c where c.regNo >= '320100100' and c.regNo < '320100200';
嵌套数据函数

嵌套数据函数用于访问内嵌式的数据结构,包括数组、映射、重复标量类型。不要在GROUP BY、ORDER BY子句或者在比较操作符中使用前述内嵌数据。Drill不支持 VARCHAR:REPEATED之间的比较。

FLATTEN

把嵌套数据结构分解为单独的记录(行),示例:

SQL
1
2
-- 每个企业包含多个股东,股东为数组
SELECT FLATTEN(stocks) FROM bais.corps  WHERE stocks IS NOT NULL;
KVGEN

从一个映射中抽取键值对

REPEATED_COUNT

返回数组的长度: REPEATED_COUNT (array)

REPEATED_CONTAINS

在数组中搜索指定的关键字: REPEATED_CONTAINS(array_name, keyword),返回布尔值

常见问题
零散问题
无法启动:Drillbit is disallowed to bind to loopback address in distributed mode.

原因:DNS将当前主机名解析到本地环回地址,可能需要更改/etc/hosts文件

无法启动:Could not get canonical hostname.

原因:DNS没有正确配置

解决办法:如果网络中没有启用DNS服务,可以静态的修改/etc/hosts文件

Failed to encode '***' in character set 'ISO-8859-1'

可以用这种方式来指定中文查询条件:

SQL
1
select * from bais.trades where name like _UTF16'%农产品%';
MongoDB问题
身份验证失败:com.mongodb.MongoSecurityException: Exception authenticating MongoCredential

原因:如果分片集群启用了身份验证,不但需要建立集群上的用户,还要为每个复制集创建本地用户。如果报错信息中有servers=[{address=****而且地址是分片的(而不是mongos的)地址,说明就是分片的身份验证出错。

← Gorilla学习笔记
Apache Curator学习笔记 →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • OpenTSDB学习笔记
  • Kafka Streams学习笔记
  • ElasticSearch学习笔记
  • InfluxDB学习笔记
  • Apache Kafka学习笔记

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • Ceph学习笔记 27 people like this
  • 基于Calico的CNI 27 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2