一个Presto连接器是连接Presto引擎与外部目录的插件。Presto连接器可用于各种数据源,包括关系型数据库、NoSQL数据库和文件系统。
在本章中,您将学习如何实现自定义连接器。首先,我们将描述由Presto提供的服务提供者接口(SPI)的概念,该接口定义了在Presto中构建自定义连接器、类型、函数和系统访问控制的接口。
然后,我们将关注连接器的概念以及它在Presto中的实现方式。接下来,您将学习如何实现自定义连接器和一种基于Apache Thrift的替代实现,该实现可以在Presto和由Thrift支持的任何语言编写的外部服务器之间进行通信,例如Python、PHP等。
最后,我们将专注于Apache Pinot,这是一个实时分布式数据存储,以及如何将其连接到Presto。
服务提供者接口(Service Provider Interface,简称SPI)
SPI(Service Provider Interface)是一个你可以使用的接口,用于通过第三方组件扩展框架。如图3-1所示,Presto实现了自己的SPI。Presto SPI位于Presto服务器内部,负责管理Presto核心与外部服务提供者之间的通信。

一个希望与Presto通信的服务提供者必须实现一个插件模块,该模块与Presto SPI进行交互。然后,Presto SPI通过API将由服务提供者实现的功能提供给Presto核心。
最流行的Presto插件包括连接器、类型、函数和系统访问控制。在本节的其余部分,我们将对每个插件进行概述。有关更多详细信息,请参阅Presto文档。
- 连接器
连接器使Presto能够与外部系统进行数据读写交互。正如我们将看到的,连接器负责向Presto公开表元数据,如模式、表和列定义,以及将来自外部数据源的数据映射到Presto数据类型。
- 类型
类型是一种插件,允许您在SQL语言中实现自定义数据类型。Presto已经定义了许多内置类型,例如BOOLEAN、INTEGER、VARCHAR等。并非所有连接器都需要实现给定的数据类型。
- 函数
Presto提供许多用于访问数据的函数。示例函数包括数学函数、聚合函数、字符串函数等。通过编写自己的函数插件,您可以扩展可用函数的集合。
- 系统访问控制
Presto定义了一些访问控制策略,允许您在Presto集群中定义具有不同特权的不同角色。您可以编写自定义插件来指定系统访问控制。我们将在第7章中重点关注这个方面。
连接器架构
图3-2显示了Presto与连接器之间调用的流程。当客户端在Presto中运行查询时,Presto协调器通过检索每个连接器的有关目录的有用元数据(Metadata API)来解析和分析查询(Parser/Analyzer)。元数据包括可用表的列表、列定义等信息。然后,Presto协调器通过询问Data Location API获取要发送给工作节点的各个块,规划如何运行查询(Planner),优化查询,并定义如何在工作节点之间分发查询(Scheduler)。工作节点在收到其块后通过查询目录(通过Data Stream API)来运行任务。查询的结果被组织并发送回协调器,协调器将其发送给客户端。

热门连接器
Presto提供许多连接器,用于不同类型的目录,包括关系型和非关系型数据库、实时数据源以及其他对象存储系统,如Hadoop分布式文件系统(HDFS)。可用连接器的列表不断增加;有关支持的连接器的更多详细信息,请参阅Presto文档。在本书中,我们将重点关注三个连接器:Thrift、Apache Pinot和Apache Hudi。我们将在本章中介绍Thrift和Apache Pinot,而在第5章中介绍Apache Hudi。由于其重要性,我们将在本章的一个单独部分中描述Apache Pinot。表3-1提供了本书中使用的连接器的简要描述。

在第2章中,我们了解了如何将连接器插入Presto。只需在Presto安装目录的目录中添加一个名为mycatalog.properties的新配置文件到您的目录中。每个配置文件必须至少定义目录名称(例如,connector.name=tpch)。
Thrift
Apache Thrift是一个用于构建可扩展跨语言服务的软件框架。描述Apache Thrift及其架构超出了本书的范围。有关更多详细信息,您可以参考Thrift的官方文档。但是,对于我们的目的,只需知道Apache Thrift包括一个编译器,该编译器以接口定义语言(IDL)中定义的一些抽象数据类型作为输入。然后,编译器将生成与输入相关联的存根代码,支持的任何语言,例如Python、PHP、Java等。使用生成的存根代码来实现您服务所需的任务。
如果您想要实现跨平台的应用程序,Apache Thrift是一个非常有用的工具,因为它允许轻松创建相互通信的服务和应用程序,而不受语言或平台的限制。Thrift还专为高性能而设计,实际上非常易于使用和非常灵活,因为您可以将其用于各种用途。
结合Thrift和Presto使您能够轻松地从Thrift支持的任何语言调用Presto,使其成为开发可扩展、跨语言应用程序的理想解决方案。
Presto实现了Thrift连接器,您可以像使用其他连接器一样使用它。指向Presto协调器的etc/catalogs/目录,并创建一个名为thrift.properties的文件,具有以下最小配置:
ini
connector.name=my-thrift-connector
presto.thrift.client.addresses=host:port,host:port
除了连接器名称外,还要定义由Thrift编译器生成的存根代码的主机地址列表。有关所有支持的属性列表,请参阅Presto文档。
要实现Thrift服务,请从书的GitHub存储库(03/thrift/PrestoThriftService.thrift)下载Presto IDL服务,并将其放在文件系统的任何位置。然后运行以下命令生成存根代码:
css
thrift --gen java PrestoThriftService.thrift
该命令将在Java中生成存根代码。将关键字java更改为您喜欢的语言,以生成该语言的代码。您可以从书的GitHub存储库(03/thrift/thrift-stub-java目录)下载Java中的存根代码。
获得存根代码后,根据外部目录的要求实现服务。可以使用PrestoDB GitHub存储库上的presto-thrift-testing-server模块作为参考。
编写自定义连接器
假设您有一个专有数据库,并且希望将其连接到Presto,但不幸的是,所有可用的Presto连接器都与您的数据库不兼容。在这种情况下,最好的选择是实现自己的连接器,将您的数据库直接映射到Presto。
在本节中,您将学习如何从头开始为Presto构建一个自定义连接器。在高层次上,连接器由四个主要组件组成:
- 插件和模块
- 配置
- 元数据
- 输入/输出
为了讨论构成连接器的组件,我们将使用"示例HTTP连接器"。这是一个基本的连接器,通过HTTP读取CSV文件。您可以在PrestoDB GitHub存储库的presto-example-http模块下查看其源代码。
先决条件
由于Presto是用Java编写的,因此您必须使用Java编写自定义连接器。此外,由于Presto是作为标准Maven项目实现的,为了使您的连接器项目正常工作,请安装Apache Maven。还要下载Presto JAR文件并将其包含在项目库中。可选择使用IDE编辑代码。在本书中,我们将使用IntelliJ IDEA。我们建议使用IDE,因为它可以简化Maven项目的管理。如果您不使用IDE,请确保手动设置所有环境,包括JDK和所需的库。
要创建一个新项目,请启动IntelliJ IDEA或您喜欢的IDE,然后选择File > New > Project > New Project。然后,填写表单,选择Maven作为构建系统,然后单击Create。现在,将Presto库添加到您的项目中。如果您没有安装任何JDK,请选择JDK > Download JDK,然后选择版本1.8。
创建项目后,将Presto库添加到项目中。单击窗口左侧的项目名称,然后选择Open Module Settings > Libraries > + > Java。从文件系统中选择Presto JAR文件,然后单击OK。项目可能还需要其他外部库。通过选择Open Module Settings > Libraries > + > From Maven,然后搜索所需的库来添加它们。
要在IntelliJ IDEA中加载"示例HTTP连接器",请下载Presto源代码,并通过选择File > New > Project > New Project from existing sources > Import project from external model > Maven 来加载它。
插件和模块
插件和模块指定了构成您连接器的顶级类,使得Presto能够初始化您的目录。在"示例HTTP连接器"中,参与此级别的主要类包括ExamplePlugin、ExampleConnectorFactory、ExampleModule、ExampleConnector和ExampleHandleResolver,如图3-3所示。
在图中,插件和模块级别涉及的类显示为黑色方框。灰色方框显示了由这些类创建、配置、指向或返回的类。

ExamplePlugin
ExamplePlugin这个类实现了Presto Plugin接口,该接口告诉Presto此插件具有哪些功能。由于这个示例是一个连接器,ExamplePlugin只实现了getConnectorFactory()方法,并返回ExampleConnectorFactory。如果此插件实现了其他功能,如函数和类型,您应该通过其他方法在这里实现它们。
ExampleConnectorFactory
ConnectorFactory是一个基础接口,旨在为特定提供程序创建连接器。ExampleConnectorFactory类实现了Presto ConnectorFactory接口,并提供以下基本类:
- getName():返回连接器的名称,例如 example-http。连接器名称在Presto安装中唯一标识此连接器。在创建Presto目录时,请使用此处定义的连接器名称,如第2章所述。
- getHandleResolver():创建一个新的ExampleHandleResolver对象,告诉Presto使用哪些类来处理此连接器。
- create():创建运行连接器所需的模块。
Presto使用Google Guice进行依赖注入。解释这个项目(以及通常的依赖注入)超出了本书的范围,但简而言之,您定义连接器所需的模块(我们将在下面看到),然后使用注入器创建其实例。Guice分析模块以及需要哪些类,根据需要创建实例。Guice在启动时报告任何缺失的依赖关系,然后程序崩溃。有关更多详细信息,请参阅Guice项目文档。
ExampleModule
这个类实现了通过Google Guice定义的Module接口。在configure()方法中,您必须配置使用Google Guice的任何类,如下所示:
arduino
public void configure(Binder binder)
{
binder.bind(ExampleConnector.class).in(Scopes.SINGLETON);
// 其他配置...
}
ExampleConnector
这个类实现了Presto Connector接口,并列出了连接器支持的功能。Presto使用以下四个对象实例化此类:LifeCycleManager,以及MetaData、SplitManager和RecordSetProvider接口的自定义实现。
ExampleConnector类实现了返回实例化对象的方法,以及开始事务和关闭事务的方法:
typescript
public class ExampleConnector implements Connector
{
@Inject
public ExampleConnector(
LifeCycleManager lifeCycleManager,
ExampleMetadata metadata,
ExampleSplitManager splitManager,
ExampleRecordSetProvider recordSetProvider){...}
public ConnectorTransactionHandle
beginTransaction(IsolationLevel isolationLevel, boolean readOnly){...}
public ConnectorMetadata
getMetadata(ConnectorTransactionHandle transactionHandle){...}
public ConnectorSplitManager getSplitManager(){...}
public ConnectorRecordSetProvider getRecordSetProvider(){...}
public final void shutdown(){...}
}
在构造函数前的@Inject装饰符告诉Google Guice将该类添加到注入的依赖项中。
ExampleHandleResolver
这个类实现了Presto ConnectorHandleResolver接口,被Presto用于确定实现的处理程序。最少,用户必须提供以下处理程序的实现:ConnectorTableHandle、ConnectorTableLayoutHandle、ColumnHandle、ConnectorTransactionHandle 和 ConnectorSplit。这些类稍后在本节中会有更详细的解释。
对于每个实现的处理程序,ExampleHandleResolver必须定义一个返回它的方法:
typescript
@Override
public Class<? extends ConnectorTableHandle> getTableHandleClass()
{
return ExampleTableHandle.class;
}
配置
配置包括用于指定目录配置的类,例如外部数据库的URL和凭据,以及会话属性。通常,您会看到与配置相关的三种Presto类:连接器属性(ExampleConfig)、会话属性(SessionProperties)和表属性(TableProperties)。
ExampleConfig
连接器属性提供由您的连接器使用的静态信息,通常是连接信息,如URI和登录信息。ExampleConfig类定义了在Presto的目录配置文件(例如example-http.properties)中使用的设置和获取属性的方法。
Example HTTP连接器定义了ExampleConfig类以实现连接器的属性。例如,要设置名为metadata-uri的属性,ExampleConfig类定义了以下方法:
kotlin
@Config("metadata-uri")
public ExampleConfig setMetadata(URI metadata)
{
this.metadata = metadata;
return this;
}
@Config注解指定了要在example-http.properties中设置的属性名称,而getter上的其他注解可以对值强制执行限制。例如,@NotNull告诉Presto此配置值不能为空,或者@Size(min = 1)强制用户不能设置小于1的任何值。
SessionProperties
会话属性是由用户为每个客户端会话指定的项目,通常用于根据用户想要运行的查询类型调整配置设置或启用实验性功能。通过Shell设置会话属性如下:
ini
SET SESSION connectorname.propertyname = 'value';
Example HTTP连接器没有定义任何会话属性。然而,为了了解会话属性的工作原理,我们定义了一个简单的会话属性LOG_VERBOSITY,如果设置为true,则启用日志。
ExampleSessionProperties的构造函数创建了所有可用属性的列表。每个属性都有一个名称、描述、SQL数据类型、Java数据类型、默认值、会话属性是否隐藏以及编码器/解码器函数。例如,创建LOG_VERBOSITY会话属性如下:
javascript
PropertyMetadata<Boolean> s1 = booleanProperty(
LOG_VERBOSITY,
"Set to true to enable log verbosity.",
true,
false);
您可以使用PropertyMetadata构造函数创建属性。为了检查是否启用LOG_VERBOSITY会话属性,ExampleSessionProperties定义了以下方法:
typescript
public static boolean isLogVerbosityEnabled(ConnectorSession session)
{
return session.getProperty(LOG_VERBOSITY, Boolean.class);
}
TableProperties
表属性是附加到您外部系统的特定表的属性,例如用于指定表如何分区的属性。表属性类的结构类似于会话属性(查看Hive连接器定义的HiveTableProperties的示例,以了解其结构)。
在WITH子句中使用表属性进行表定义:
ini
CREATE TABLE foo (a BIGINT)
WITH
(
myTableProperty = 'value',
myOtherTableProperty = 'othervalue'
);
元数据
元数据包括定义数据模型的类,以及向Presto公开数据模型的处理程序。此外,为了管理数据模型及其处理程序,您必须实现两个类:Metadata 和 Client。图3-4显示了在Example HTTP连接器的元数据级别涉及的主要类。

ExampleClient包含一个表示数据模型的Supplier映射。我们将在本章后面看到数据模型的详细信息。ExampleMetadata包含对ExampleClient的指针,并在需要时创建ExampleTableLayoutHandle、ExampleTableHandle和ExampleColumnHandle的新实例。
数据模型
Presto使用关系模型表示数据;因此,每个Presto连接器必须通过关系模型公开数据,尽管连接器提供的数据的原始表示可能是不同的。关系模型以模式、表和列的形式表示数据。每个模式可以有一个或多个表,每个表可以有一个或多个列。每个表的实际数据可以存储在一个或多个物理对象中。
在您的连接器中,您必须至少定义Table和Column类作为带有@JsonCreator注解的普通Java对象(POJOs)。这个注解被Presto用于将POJO序列化为JSON对象,在协调器和工作节点之间传递。
处理程序
为了使Presto访问数据模型的类,您还必须实现它们的相关处理程序,这些处理程序是Presto在其处理中使用的类,例如解析、计划等:TableHandle、ColumnHandle 和 TableLayoutHandle。
图3-5显示了在Example HTTP连接器中检索表处理程序的调用流程。

用户通过调用ExampleMetadata对象的getTableHandle()方法启动流程,指定要检索ExampleTableHandle的模式和表名。存储指向ExampleClient对象的指针的ExampleMetadata对象将此调用转换为对ExampleClient对象的getTable()方法的调用。ExampleClient对象提取ExampleTable并将其返回给ExampleMetadata对象,以检查返回的对象是否为null。如果不为null,ExampleMetadata对象将创建ExampleTableHandle的新实例并将其返回给客户端。
ExampleMetadata
该类实现了ConnectorMetadata接口,该接口包含将模式、表和列信息暴露给Presto的所有方法。根据您将外部系统建模为Presto的关系模型的方式,实现这些方法中的每一个。
ExampleClient
该类实现了获取模式、表和列定义的功能。在Example HTTP连接器中,由于它是一个示例连接器,该类的实现相当轻量级。在实际的连接器中,您的客户端通常会对外部系统进行API调用,将其元数据模型映射到Presto的关系元数据模型。如图3-4所示,ExampleClient维护一个映射来表示目录的逻辑结构。
输入/输出
输入/输出指的是从外部系统读取和/或将数据写入Presto的类。
在概念上,要从表中读取记录,首先将表扫描拆分为多个可由Presto工作节点并行运行的拆分对象。然后,对于每个拆分,为拆分创建一个记录集,记录集包含一个游标,该游标迭代传递给Presto的数据行。
图3-6显示了在Example HTTP连接器的输入/输出级别涉及的主要类,这些类仅实现了读取操作。

ExampleSplitManager创建了N个ExampleSplit对象,其中N是表中源的数量。对于每个拆分,ExampleRecordSetProvider创建一个新的ExampleRecordSet。每个ExampleRecordSet对象维护一个指向其关联的ExampleSplit的指针。此外,每个ExampleRecordSet对象创建一个新的ExampleRecordCursor对象,执行从表中进行的原始读取操作。
ExampleSplitManager
该类实现了ConnectorSplitManager接口,具有一个方法getSplits(),该方法指定了如何将连接器提供的表拆分为多个可以由Presto工作节点并行读取的部分。此方法的输入包括ConnectorSession(可用于访问会话属性)、正在扫描的TableLayoutHandle和上下文。Presto获取getSplits()方法返回的拆分,并将它们传递给RecordSetProvider。
ExampleSplit
该类实现了ConnectorSplit接口,与整个表的特定块相关联。与元数据类一样,它是一个包含模式、表和要读取的URI的Jackson POJO对象。
ExampleRecordSetProvider 和 ExampleRecordSet
这个ExampleRecordSetProvider实现了ConnectorRecordSetProvider接口,并通过getRecordSet()方法从给定的拆分创建一个RecordSet。它还包括一个列的列表,这些列预计将从表中读取并出现在记录集中。这些列的列表可能是用户通过SELECT *等方式选择的列。
ExampleRecordSet实现了RecordSet接口,用于实例化一个ExampleRecordCursor,该游标在拆分上进行迭代以提供数据行。
ExampleRecordCursor
这个类实现了RecordCursor接口,执行原始的读取操作。Example HTTP连接器读取CSV文件。因此,ExampleRecordCursor类必须实现迭代文件的列和行以返回所需值的方法。
当实例化一个ExampleRecordCursor对象时,它将源文件的所有行加载到字符串迭代器中:
scss
public ExampleRecordCursor(
List<ExampleColumnHandle> columnHandles,
ByteSource byteSource)
{
...
lines = byteSource.asCharSource(UTF_8).readLines().iterator();
...
}
根据要执行的操作,ExampleRecordCursor迭代此迭代器以提取所需的信息。例如,在读取CSV文件时,使用以下方法前进到下一个位置:
arduino
public boolean advanceNextPosition()
{
if (!lines.hasNext()) {
return false;
}
String line = lines.next();
fields = LINE_SPLITTER.splitToList(line);
return true;
}
LINE_SPLITTER对象是ExampleRecordCursor的静态成员,简单地分隔行的列:
ini
private static final Splitter LINE_SPLITTER = Splitter.on(",").trimResults();
部署您的连接器
要部署您的连接器,请使用Maven使用presto-plugin打包构建您的项目。要配置pom.xml文件,请查看presto-example-http项目的pom.xml文件,并将其用作起点,根据需要修改项目名称和依赖项。 构建项目有两种选择:使用命令行或使用IntelliJ。当使用命令行中的Maven时,只需从项目目录运行以下命令:mvn package
。如果使用IntelliJ,请按照以下步骤操作:
- 在项目右侧打开Maven Projects侧边栏。
- 选择您的项目并导航到生命周期部分。
- 双击package。
构建完成后,将生成的target文件夹及其内容复制到Presto安装插件目录。然后,在etc/catalogs目录中添加连接器的目录,并重新启动Presto。
Apache Pinot
Apache Pinot,简称Pinot,是一个实时分布式在线分析处理(OLAP)数据存储,旨在提供超低延迟的分析,即使在处理极高吞吐量时也是如此。您可以使用Pinot摄取各种数据源,包括实时数据源(如Apache Kafka)和批量数据源(如Hadoop HDFS)。在实时分析场景中,Pinot是数据湖架构的组件之一,通常连接到Amazon S3存储桶。我们将在第5章介绍如何设置数据湖架构。
本章重点介绍Apache Pinot,因为它非常适合涉及高维数据的实时用例。此外,Pinot的快速查询能力使其成为Presto的理想数据源。因此,当Pinot和Presto一起使用时,它们提供了一个强大的平台,用于对大规模数据集进行快速高效的分析查询。
Presto提供了与Pinot的连接器。在本节中,我们将看到如何配置Pinot与Presto一起使用。本书不涵盖Pinot及其架构的详细说明。您可以参考Pinot的官方文档获取更多详细信息。
设置和配置Presto
Pinot既不提供完整的ANSI SQL支持,也不提供类似ODBC/JDBC的标准数据库访问API支持。连接Pinot到Presto弥补了这个不足,因为用户可以使用Presto功能访问Pinot,包括ANSI SQL和ODBC/JDBC支持。
此外,将Presto连接到Pinot有两个好处:
- 可以在Pinot中使用相同的SQL代码,也可以在数据湖架构或其他数据源中使用。例如,您可能希望在新的实时数据上运行查询,然后在湖屋中的历史数据上运行相同的查询(即"一条SQL规定它们所有")。
- 跨Pinot和另一个数据源的联合查询提供更多的相关性或洞察力。
设置Pinot
我们将Pinot配置为在第2章中部署的Kubernetes集群的一个节点。为了在本地机器中保留资源,我们将在单个节点上部署Pinot。在实际的生产环境中,Pinot会部署在一个节点集群中。 本节中使用的代码位于目录03/presto-and-pinot中,其中包含Pinot配置文件和Presto配置文件。
配置Pinot
Pinot由四个主要模块组成:控制器(controller)、代理(broker)、服务器(servers)和Zookeeper。每个模块的详细描述超出了本书的范围。对于本书而言,知道这些模块在一个集群中组织,并且控制器是协调器,类似于Presto中的Presto协调器即可。
要在本地机器上部署Pinot,请按照官方Pinot文档的说明进行。但是,如果您的机器上没有足够的资源(至少16 GB的RAM)同时运行Pinot和Presto,请按照本节中的步骤进行操作。该步骤描述了如何在单个Pod中部署所有Pinot模块(pinot-deployment.yaml):
yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: pinot
spec:
replicas: 1
template:
metadata:
labels:
app: pinot
spec:
containers:
- name: pinot
image: apachepinot/pinot:latest
command: ["/opt/pinot/bin/pinot-admin.sh"]
args: ["QuickStart", "-type", "batch"]
ports:
- containerPort: 9000
resources:
requests:
memory: "2Gi"
limits:
memory: "2Gi"
使用ReplicationController来部署Pinot集群。在安装了apachepinot/pinot:latest
镜像之后,脚本会运行命令/opt/pinot/bin/pinot-admin.sh QuickStart -type batch
,该命令安装所有组件并向数据库添加一些示例表。有关详细信息和示例,请参阅官方文档。根据您机器的要求,调整资源在resources
部分的设置。
使用Presto配置Pinot
为了使Presto与Pinot配合使用,将Pinot添加为Presto配置中的新目录。在presto-config-map.yaml中添加一个新条目:
ini
pinot.properties: |
connector.name=pinot
pinot.controller-urls=pinot:9000
pinot.controller-rest-service=pinot:9000
请参考Presto文档获取额外的配置选项。
为了在协调器和工作节点中使用Pinot目录,将以下条目添加到presto-coordinator.yaml和presto-workers.yaml中的volumeMount:
yaml
containers:
- name:
volumeMounts:
- name: pinot
mountPath: "/opt/presto/etc/catalog/pinot.properties"
subPath: pinot.properties
...
volumes:
- name: pinot
configMap:
name: presto-config
items:
- key: "pinot.properties"
path: "pinot.properties"
Presto-Pinot查询实例
现在配置已经完成,我们将运行两个样例查询。使用Presto协调器中提供的Presto客户端来运行查询。
首先,列出Pinot中所有可用的表:
sql
presto> show tables from pinot.default;
Table
-------------------------
airlinestats
baseballstats
billing
dimbaseballteams
githubcomplextypeevents
githubevents
starbucksstores
(7 rows)
使用baseballstats表进行下一个查询。为了了解Presto如何运行查询,请在查询之前使用EXPLAIN运算符。例如,要列出表中每个球员名称重复的次数,请运行以下查询:
vbnet
EXPLAIN
SELECT playerName, count(1)
FROM pinot.default.baseballStats
GROUP BY playerName;
该命令生成一个包含对Presto组件的嵌套调用的长日志。Presto将查询从上层(TableScan)传播到底层(PinotColumnHandle和GeneratedPinotQuery)。以下代码片段显示了伪代码中的调用流程:
ini
TableScan ->
TableHandle ->
expectedColumnHandles ->
PinotColumnHandle{columnName="playerName", ...}
PinotColumnHandle{columnName="count", ...}
layout ->
PinotTableHandle ->
expectedColumnHandles ->
PinotColumnHandle{columnName="playerName", ...}
PinotColumnHandle{columnName="count", ...}
pinotQuery ->
GeneratedPinotQuery
{
query=SELECT "playerName", count(*)
FROM baseballStats
GROUP BY "playerName"
LIMIT 10000,
}
总结
在本章中,您学习了如何在Presto中实现自定义连接器,既使用Presto SPI,又使用Thrift。
SPI要求您使用Java编写自定义连接器,通过实现不同的类,包括四个主要组件:插件和模块、配置以及输入/输出。对于每个组件,您必须实现一些类,这些类使您的目录与Presto核心之间进行通信。尽管您的原始目录不是关系型的,但您的自定义连接器必须使用关系型数据模型来公开数据。
此外,您学习了如何使用Apache Thrift编写自定义连接器,这是一个使开发人员能够构建可扩展的跨语言服务的软件框架。通过Thrift连接器,Presto可以与使用Java以外的语言编写的外部服务进行通信。
您还学习了如何将Apache Pinot(一个实时分布式OLAP数据存储)连接到Presto。您在Kubernetes上设置了一个运行Pinot实例的计算机,并将其与您在第2章部署的Presto集群连接起来。
在第4章中,您将学习一些连接客户端到Presto的高级技术。