《Learning and Operating Presto 》第四章:客户端连接

Presto客户端是一个用于查询Presto并显示查询结果的进程,用于各种目的,例如数据分析、即席查询等。Presto提供了各种客户端,使用不同的编程语言编写,包括REST API、R、Python、JDBC、Node.js和ODBC。

这一章分为两个部分。在第一部分中,您将学习如何部署Presto客户端。虽然您可以将Presto客户端部署为在现有集群节点上运行的单独进程,但在本章中,您将在不同的节点上实现客户端,以模拟外部应用程序访问集群。我们将重点介绍如何在REST API、Python、R、JDBC、Node.js和ODBC中实现客户端。您可以轻松扩展所描述的过程以支持Presto支持的其他编程语言。

在第二部分中,您将使用Python实现一个实用的Web服务,查询Presto并在简单的仪表板中显示结果。这个例子的目标是展示Presto客户端的潜力。

搭建环境

为将Presto客户端添加为Presto集群的节点,首先需要设置环境。部署以下在第3章中已实现的三个组件:

  1. Presto客户端
  2. 包含Presto客户端的Docker镜像
  3. 在Presto集群中运行Docker镜像的Kubernetes节点

本节使用的代码可在书籍存储库的04目录中找到,其中包含了所有描述的Presto客户端的配置文件。

Presto客户端

Presto客户端连接到Presto,运行查询并显示结果。您可以使用自己喜欢的编程语言编写Presto客户端代码,并将其保存到将作为独立卷挂载在Kubernetes节点上的目录中。您还可以选择编写一个通过HTTP提供访问权限的Web应用程序或服务。我们将在本章后面看到如何部署一个客户端Web服务。或者,您也可以使用终端访问Presto客户端。

Docker镜像

Docker镜像包含运行Presto客户端所需的环境。使用以下Dockerfile模板:

sql 复制代码
FROM <basic_image>
RUN apt-get update && \
<install required libraries>

例如,要构建R客户端的镜像,请编写以下Dockerfile:

sql 复制代码
FROM r-base
RUN apt-get update && \
apt install -y build-essential libcurl4-gnutls-dev libxml2-dev libssl-dev
RUN R -e "install.packages('RPresto')"

要构建您的Docker镜像,请在终端中运行以下命令:

erlang 复制代码
docker build -t client-presto .

Kubernetes节点

要在Presto集群中部署Kubernetes节点,请编写一个.yaml配置文件,简单地包装Docker镜像:

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-client
  labels:
    app: my-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-client
  template:
    metadata:
      labels:
        app: my-client
    spec:
      containers:
      - name: my-client
        image:  client-presto:latest
        imagePullPolicy: Never
        command: [ "sleep" ]
        args: [ "infinity" ]

命令 sleep infinity 确保Kubernetes保持您的客户端处于活动状态。或者,如果您的客户端运行服务,请修改配置代码以部署服务。

要在Docker容器中运行自定义脚本,请挂载本地卷:

yaml 复制代码
spec:
 containers:
 - name: client
   # 根据客户端类型添加详细信息
   volumeMounts:
    - name: scripts
      mountPath: "/path/in/the/container"

 volumes:
  - name: scripts
    hostPath:
      path: "/path/to/scripts/in/the/host"

通过运行以下命令部署客户端:

arduino 复制代码
kubectl apply -f client.yaml --namespace presto

部署客户端后,登录到客户端并在挂载的目录中运行脚本。

Presto的可用客户端

这一部分概述了如何使用现有的客户端库来建立与 Presto 集群的连接。我们将使用 Presto 支持的不同编程语言。从图书的 GitHub 存储库中下载您偏好的语言中的运行示例,位于目录 04/<language>_client。如果您对某些语言不感兴趣,可以随意跳过。

REST API

Presto协调器包含支持REST API端点的HTTP服务器。客户端与Presto协调器之间的所有通信都使用HTTP协议。要使用REST API运行Presto客户端,至少需要指定Presto协调器的URL、查询和一个包含要查询的目录和模式的最小标头:

lua 复制代码
curl -d "SELECT * FROM customer LIMIT 5" \
--request POST \
-s "presto-coordinator:8080/<endpoint>" \
-H "X-Presto-User: client" \
-H "X-Presto-Catalog: tpch" \
-H "X-Presto-Schema: sf1"

使用-H "X-Presto-User: client"指定用户。默认情况下,Presto接受任何用户,因此可以写入任何名称。在第7章中,您将看到如何在Presto中配置特定用户。

如果对REST API的调用成功,Presto将返回一个JSON对象,其中nextUri键已设置。使用与nextUri键相对应的值作为URL再次调用Presto。稍后在本节中将为此提供一个示例。

REST API为您提供许多端点,例如:

  • /v1/node:获取有关节点的信息。
  • /v1/statement:运行查询。
  • /v1/query:获取有关最近查询的指标。可选择指定查询ID以获取有关特定查询的信息。
  • /v1/thread:获取有关线程的信息。
  • /v1/task:获取有关任务的信息。

迭代对Presto的先前调用,直到响应JSON对象中不存在nextUri键为止。如果最后一个调用成功,返回的对象将包含data键的查询结果值。

arduino 复制代码
curl -s "URL contained in nextUri"

以下代码显示了在Python中调用REST API的完整示例:

运行对REST API的第一个调用:

makefile 复制代码
import requests
import time

url = "http://presto-coordinator:8080/v1/statement"

headers = {
    "X-Presto-User": "client",
    "X-Presto-Catalog": "tpch",
    "X-Presto-Schema": "sf1"
}

sql = "SELECT * FROM customer LIMIT 5"

resp = requests.post(url, headers=headers, data=sql)
json_resp = resp.json()

迭代nextUri键,直到其不存在。使用time.sleep(0.5)等待数据。如果您的客户端没有收到任何数据,请增加此值。

ini 复制代码
while 'nextUri' in json_resp:
    time.sleep(0.5)
    new_url = json_resp['nextUri']
    resp = requests.get(new_url)
    json_resp = resp.json()

获取最终数据:

scss 复制代码
data = json_resp['data']
for i in range(0, len(data)):
    print(data[i])

Presto REST API提供许多其他参数。阅读Presto文档以获取更多详细信息。

Python

安装presto-python-client库。在Dockerfile中运行以下命令:

pip install presto-python-client

然后,按以下方式连接到Presto:

ini 复制代码
import prestodb

conn = prestodb.dbapi.connect(
    host='presto-coordinator',
    port=8080,
    user='client',
    catalog='tpch',
    schema='sf1',
)

要运行查询,请检索游标:

ini 复制代码
cur = conn.cursor()
cur.execute('SELECT * FROM customer LIMIT 5')
rows = cur.fetchall()

R

安装RPresto库。在Dockerfile中运行以下命令:

arduino 复制代码
RUN R -e "install.packages('RPresto')"

要在R中查询Presto,请首先导入所需的库:

scss 复制代码
library(RPresto)
library(DBI)

然后连接到Presto服务器:

ini 复制代码
con <- DBI::dbConnect(
  drv = RPresto::Presto(),
  host = "presto-coordinator",
  port = 8080,
  user = "r-client",
  catalog = "tpch",
  schema = "sf1"
)

要运行查询,请使用DBI::dbGetQuery()函数:

arduino 复制代码
DBI::dbGetQuery(con, "SELECT * FROM customer LIMIT 5")

JDBC

使用Presto JDBC驱动程序com.facebook.presto.jdbc.PrestoDriver。如果使用Maven,请在pom.xml文件中添加以下依赖项:

xml 复制代码
<dependencies>
  <dependency>
    <groupId>com.facebook.presto</groupId>
    <artifactId>presto-jdbc</artifactId>
    <version>0.276</version>
  </dependency>
</dependencies>

如果不使用Maven,请从Presto网站下载presto-jdbc-0.276.jar文件,并将其添加到Java应用程序的类路径中。请将Presto的版本替换为最新版本(在撰写本章时为0.276)。

在主Java应用程序中,定义连接到Presto的URL,并通过Connection连接到Presto:

java 复制代码
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;

String url = "jdbc:presto://presto-coordinator:8080/tpch/sf1";

try {
  Class.forName("com.facebook.presto.jdbc.PrestoDriver");

  Connection connection = DriverManager.getConnection(url, "test", null);
}
catch(SQLException e){
  e.printStackTrace();
}
catch(ClassNotFoundException e){
  e.printStackTrace();
}

在URL字符串中,指定目录(tpch)和模式(sf1)。然后运行您的查询:

ini 复制代码
String sql = "SELECT * FROM customer LIMIT 5";

try {
  Statement statement = connection.createStatement();
  ResultSet rs = statement.executeQuery(sql);
  while (rs.next()) {
    System.out.println(rs.getString(1));
  }
}
catch(SQLException e){
  e.printStackTrace();
}

该示例打印查询结果集中每个结果的第一列。

Node.js

安装presto-client库:

npm install -g presto-client

在主JavaScript应用程序中,导入库并创建一个新的Client()对象:

php 复制代码
var presto = require('presto-client');
var client = new presto.Client({
  user: 'myuser',
  host: 'http://presto-coordinator',
  port: '8080'
});

然后执行任何查询:

lua 复制代码
client.execute({
  query:   'SELECT * FROM customer LIMIT 5',
  catalog: 'tpch',
  schema:  'sf1',
  source:  'nodejs-client',
  data:    function(error, data, columns, stats){ console.log(data); },
  success: function(error, stats){console.log(stats);},
  error:   function(error){console.log(error);}
});

ODBC

Open Database Connectivity (ODBC) 是一种标准的数据库访问方法,它使应用程序能够访问各种数据库格式的数据。许多数据库供应商,如Microsoft、Oracle和IBM,提供了ODBC专有驱动程序,以连接到任何符合ODBC标准的数据库,而不考虑数据库的底层结构或格式。

要实现Presto ODBC客户端,首先必须安装一个ODBC驱动程序。在本书中,我们使用了CData。

为了使驱动程序工作,首先安装unixodbc、unixodbc-dev和tdsodbc库。例如,在Ubuntu中,运行以下命令:

arduino 复制代码
apt-get install -y unixodbc unixodbc-dev tdsodbc

接下来,下载CData Presto驱动程序(Unix版本),安装软件包并激活许可证:

bash 复制代码
dpkg -i PrestoODBCDriverforUnix.deb
cd /opt/cdata/cdata-odbc-driver-for-presto/bin/
./install-license.sh

然后,在你喜欢的编程语言中安装用于通过ODBC驱动程序访问Presto的客户端库。例如,在Python中,安装pyodbc:

pip install pyodbc

在你的ODBC客户端应用程序中,连接到Presto数据库:

ini 复制代码
conn = pyodbc.connect("DRIVER=CData ODBC Driver for Presto;\
server=presto-coordinator;\
Port=8080;user=client;\
catalog=tpch;schema=sf1")

然后执行任何查询:

scss 复制代码
cur = conn.cursor()
cur.execute('SELECT * FROM customer LIMIT 5')
rows = cur.fetchall()
print(rows)

其他Presto客户端库

Presto支持许多其他语言,包括C、Go、PHP和Ruby。在这些语言中构建客户端的过程基本相同。请参考Presto GitHub配置文件,下载特定客户端的模板。例如,在Presto GitHub配置文件的Go存储库中使用Go客户端。

构建Python中的客户端仪表板

这一部分描述了一个实际示例,演示了如何从头开始使用Python实现一个简单的仪表板,该仪表板查询Presto。该仪表板是一个Web应用程序,连接到Presto,运行一个示例查询,并在两个独立的图表中显示查询的输出。在本节中描述的代码在书的GitHub存储库中,位于目录04/client-app。

设置客户端

该仪表板作为一个 Kubernetes 节点运行,暴露一个 HTTP 服务以访问仪表板。我们将使用以下 Python 库实现仪表板:

  • Streamlit:将 Python 脚本迅速转换为 Web 应用程序。
  • Altair:用于数据可视化的 Python 库。
  • Pandas:用于数据集操作的流行 Python 库。

为了配置客户端,请执行以下步骤:

  1. 编写 Dockerfile,将应用代码复制到 Docker 镜像中,安装所需的库,暴露 Streamlit 的监听端口,并运行应用程序:
sql 复制代码
FROM python:3.8.6
WORKDIR /app

COPY app .

RUN pip install --upgrade pip
RUN pip install presto-python-client
RUN pip install streamlit altair pandas

EXPOSE 8501

CMD ["./run.sh"]

run.sh 脚本简单地启动 Streamlit 服务器:

bash 复制代码
#!/bin/bash
streamlit run app.py --browser.serverAddress 0.0.0.0
  1. 通过在包含 Dockerfile 的目录中运行以下命令构建 Docker 镜像:
erlang 复制代码
docker build -t client-app .
  1. 使用您已经为 Python 客户端执行的过程将 client-app Docker 镜像包装成 Kubernetes 节点。由于应用程序已经在 Docker 镜像中可用,因此不需要挂载外部卷。此外,请将 Web 服务器端口暴露给外部访问:
yaml 复制代码
spec:
 containers:
 - name: client-app
   image:  client-app:latest
   ...
   ports:
     - containerPort: 8501
  1. 为 Web 应用程序构建一个服务:
yaml 复制代码
---
apiVersion: v1
kind: Service
metadata:
  name: client-service
  labels:
    app: client-service
spec:
  ports:
    - port: 8501
      protocol: TCP
      targetPort: 8501
  type: LoadBalancer
  selector:
    app: client-app

该服务暴露与原始 Web 服务器相同的端口。此外,它使用 LoadBalancer 将服务提供给 Kubernetes 集群之外的环境。

  1. 在 presto 集群中部署 client-app 节点:
arduino 复制代码
kubectl apply -f client-app.yaml --namespace presto

最后,打开浏览器并指向 http://localhost:8501 访问 Web 应用程序。

构建仪表板

客户端仪表板是一个连接到 Presto 的 Web 服务器,运行一个示例查询,并将输出显示为图形。此应用的目标是演示构建客户端应用的潜力,而不是构建数据分析的完整示例。 客户端仪表板的代码可在书籍的 GitHub 存储库的 04/client-app/app 目录下找到。该代码组织成一个名为 app.py 的单个脚本,该脚本将作为 Streamlit Web 服务器运行。具体而言,该应用执行以下操作:

  1. 连接和查询 Presto
  2. 准备查询结果
  3. 构建第一个图表
  4. 构建第二个图表

连接到 Presto 并查询

首先,应用程序导入所有必需的库:

javascript 复制代码
import prestodb
import altair as alt
import pandas as pd
import streamlit as st

然后,应用程序使用 prestodb 库连接到 Presto。使用"Python"中描述的代码执行连接。

应用程序运行一个查询,该查询列出了按最早发货日期排序的 TPC-H 目录中按日期发货的物品数量:

vbnet 复制代码
SELECT
    count(*) as nitems,
    shipdate
FROM
    lineitem
GROUP BY shipdate
ORDER BY shipdate ASC

准备查询结果

应用程序将查询结果存储在一个Pandas DataFrame中:

scss 复制代码
cur.execute(query)
df = pd.DataFrame(cur.fetchall(), columns=['nitems', 'shipdate'])

为了构建最终的图表,应用程序从'shipdate'中提取了一些信息:

scss 复制代码
df['shipdate'] = pd.to_datetime(df['shipdate'])
df['dayofweek'] = df['shipdate'].dt.day_name()
df['year'] = df['shipdate'].dt.year
df['month'] = df['shipdate'].dt.month_name()
df['weekofyear'] = df['shipdate'].dt.isocalendar().week

提取的信息包括一周中的日期(从星期日到星期六)、年份、月份和一年中的周数(从1到53的递增数字)。

构建第一个图表

第一个图表聚焦于1992年,显示了与一周内每天的发货数量相关的每周一条线:

bash 复制代码
df_1992 = df[df['year'] == 1992 ]

图表由两个部分组成。图表的第一部分显示了一年中每周的一条线:

ini 复制代码
days_of_weeks = ['Sunday', ... ,'Saturday']
bar = alt.Chart(df_1992).mark_line().encode(
    x = alt.X('dayofweek:O',
      sort=days_of_weeks,title=''
    ),
    y = alt.Y('nitems:Q', title='nitems'),
    color = alt.Color('weekofyear:N',
      scale=alt.Scale(range=['#C8C8C8']),
      legend=None
    )
)

图表的第二部分显示了所有周的发货数量的平均值:

ini 复制代码
mean = alt.Chart(df_1992).mark_line(color='black').encode(
    x = alt.X('dayofweek:O',
      sort=days_of_week,
      title=''
    ),
    y = alt.Y('weekly_count:Q', title=''),
).transform_aggregate(
    weekly_count = 'mean(nitems)',
    groupby=['dayofweek']
)

最后,应用程序将这两个部分组合在一起构建最终的图表:

ini 复制代码
chart1 = (bar + mean).properties(
    width=300,
    height=300,
    title='Number of shipped items in 1992')
)
st.altair_chart(chart1)

我们使用 st.altair_chart() 函数构建图表。图 4-1 显示了生成的图表。

构建第二个图表

第二个图表展示了一个日历热图,其中年份位于 x 轴,月份位于 y 轴:

ini 复制代码
pythonCopy code
chart2 = alt.Chart(df).mark_rect().encode(
    x=alt.X('year:O'),
    y=alt.Y('month:O', sort=days_of_weeks),
    color=alt.Color('nitems:Q', scale=alt.Scale(range=['#F5F5F5', '#000000']))
).properties(
    width=300,
    height=300,
    title='发货总数的年度月历热图'
)

st.altair_chart(chart2)

此图表使用 alt.Chart() 构建,并使用 st.altair_chart() 函数将其显示在 Streamlit 应用程序中。图表显示了发货总数的年度月历热图。

总结

在本章中,您学习了如何使用不同的语言(包括 REST API、Python、R、JDBC 和 Node.js)部署 Presto 客户端。在所有情况下,该过程都相同:构建 Docker 镜像,将其封装到 Kubernetes 节点中,然后执行该节点以向 Presto 发送查询。

您还实现了一个用于 Presto 的客户端 Web 服务,显示了一个简单的摘要报告。该 Web 服务查询了由 Presto 提供的 TPC-H 目录,并显示了与发货日期相关的一些项目数量的统计信息。

在第 5 章中,您将学习如何执行开放式数据湖分析。

相关推荐
派可数据BI可视化1 小时前
数据指标与标签在数据分析中的关系与应用
大数据·数据仓库·商业智能bi
java1234_小锋1 小时前
详细描述一下Elasticsearch索引文档的过程?
大数据·elasticsearch·搜索引擎
黄焖鸡能干四碗1 小时前
【软件设计文档】详细设计说明书模板和实际项目案例参照,概要设计说明书,需求设计书,软件设计报告(Word原件)
大数据·软件需求·设计规范·规格说明书·1024程序员节
山海青风2 小时前
使用OpenAI进行自动化报告和数据解读
数据分析
股票GPT分析2 小时前
《Python 股票交易分析:开启智能投资新时代》(二)
大数据·服务器·python·c#·fastapi
2401_881198793 小时前
图像增强夜视仪行业全面而深入的分析
数据分析
Viktor_Ye3 小时前
实现金蝶云星空与钉钉数据无缝集成的技术方法
java·大数据·钉钉
Mephisto.java4 小时前
【大数据学习 | Spark-Core】关于distinct算子
大数据·hive·hadoop·redis·spark·hbase
King's King4 小时前
蜜雪冰城也入局智慧物流,包括智能控制系统集成、机器人研发销售,开始招兵买马了...
大数据·人工智能·机器人
十二点的泡面4 小时前
大数据面试题每日练习-- Hadoop是什么?
大数据·hadoop·分布式