将数据导入 JMP 是分析工作流程的核心环节,因此 JMP 18 引入了新的数据连接器,以扩展 JMP 可访问的第三方数据源范围。JMP 18 允许对 ODBC 数据源进行更详细的配置,并简化了跨平台与同事共享这些配置以及发布到 JMP Live 的过程。我们将讨论数据连接器,不仅包括 JMP 18 中已有的功能,还包括未来 JMP 版本中对其进行扩展的计划。
早上好,或者无论您在一天中的哪个时间观看这段视频,祝您愉快。我叫尼尔·西基尔斯基 (Neal Siekierski),是 JMP 的一名软件开发人员,也是我们数据连接器项目的主要开发人员之一。今天我来这里是为了谈谈数据连接器项目,它对 JMP 18 的意义,以及它在未来发展中的影响。
我们这里有三个“C”。这就是我们希望通过 Data Connect 实现的目标。我们希望让用户能够更轻松地连接到比以往更多的数据源。我们也希望让用户能够更方便地共享这些连接。无论是与使用相同平台(Mac 或 Windows)还是不同平台的同事共享,都可以使用 JMP Live 进行共享。在为您提供更多数据源访问权限的同时,我们也希望所有操作都能在一个统一的界面中完成。
在 JMP 18 中,我们无法实现所有这些功能,因此我们转而专注于 ODBC。ODBC 是 JMP 用于与远程数据源(例如 SQL Server 或 MySQL 等数据库)通信的技术。我们选择 ODBC 是因为它本身就能访问多种类型的数据库,因此还有提升访问更多数据库的能力。
目前存在一些障碍,使得实现起来有些困难。这也是我们研究这个问题的原因之一。例如,我们发现的难点之一在于 SQL 代码。SQL 代码是一种用于从数据库获取数据的编程语言,JMP 需要生成这段代码,并通过 ODBC API 发送出去,才能获取结果并显示数据。
并非所有数据库的 SQL 代码都完全相同。例如,在 Postgres 数据库中,我们从表中获取几列数据(这里我们以一个大型类为例),代码看起来会是这样。但同样的查询在 MySQL 和其他数据库中可能看起来不一样。你可以看到 Postgres 使用的是双引号,MySQL 使用的是反引号,而 SQL Server 的语法又有所不同。
正因如此,JMP 需要知道它正在与哪个数据库通信。我们可以获取到这些信息。但为了实际使用它,JMP 需要了解每种数据库类型。如果 JMP 不了解某种数据库类型,我们会提供特定的回退行为。如果回退行为有效,那就太好了。我们会尽量设置一组合理的默认值,但有时也可能无效。在这种情况下,您就无法将查询构建器与数据源一起使用。
另一个难点在于连接字符串的使用。为了连接到数据库,JMP 必须向 ODBC 提供一个字符串,其中包含各种信息,例如连接目标、连接方式等等。一个非常简单的连接字符串如下所示。例如,我们连接的服务器是 JMP 目前可以访问的一台测试机。我们稍后会看到更多相关内容。
但更重要的是,我们还有一个驱动程序。驱动程序是一种特定的软件,它与 ODBC 连接,使您能够访问特定的数据源。ODBC 本身并不了解数据源,就像您拥有的其他软件一样,您无法在 Mac 和 Windows 上同时安装驱动程序。即使可以,也需要下载两个不同的版本。这是两个不同的软件。ODBC 的情况也非常类似。
Actual SQL Server 是由 Actual 公司开发的 SQL Server 驱动程序,专为 Mac 系统设计。如果我有一个使用此连接字符串的连接,并想与其他人共享,但他们使用的是 Windows 系统或 JMP Live,那么他们就需要修改连接字符串。
要做到这一点,他们需要知道Windows驱动程序是什么。在这个例子中,它叫做SQL Server。我可以在我的Windows机器上运行它,而且运行良好。但是,同样地,你必须知道数据库是什么。你必须知道它在每个平台上对应的驱动程序,这使得共享变得困难。
此外,不同数据库之间需要使用 JMP 指令,需要了解 JMP 指令的相关知识,以及不同的连接方式和连接字符串,这些都会造成连接共享的困难,连接所有所需的数据源也并非易事。
为了解决这个问题,我们在 JMP 18 中引入了内部数据连接器框架,并且在 ODBC 中也有一个专门的应用程序。
这些功能的核心思想是,我们提取了 JMP 根据连接类型在内部设置的所有选项。SQL Server 是一组选项,Postgres 需要另一组选项。我们将所有这些选项都公开出来,并使它们都可以单独配置。
这样一来,即使你的数据库在某些方面类似于 SQL Server,但在其他方面可能有所不同,你也可以更改一个选项,它就能正常工作。这些选项不仅仅是首选项菜单中的选项,它们是可以命名的配置,然后我们可以共享这些配置。
您可以获取一整套配置,并为其命名。这样,每当您想要连接到特定数据库时,都可以引用它;如果您想连接到其他地方,则可以使用另一个配置。由于它们都已命名,因此也更容易共享这些连接。
最后,你所做的那些设置可能因平台而异。我们刚才看到,驱动程序或其他设置可能需要有所不同。
如果只需要在 Mac 上运行某个程序,而在 Windows 上不运行任何程序,这是可以实现的。或者,如果你有更精细的需求,也可能可以做到。这些是核心思路。现在我想更详细地讨论一下,但我不会通过演示来展示所有内容。
这是 JMP。如果我们进入文件数据库,会看到一个新的菜单项“数据连接器”。点击它,会看到一个窗口,如果您用过查询生成器,这个窗口应该很熟悉。点击“新建连接”,会看到一个配置列表。
这里有几点需要注意。顶部这些配置项都是内置的,所以它们都以 com.jmp 开头。这些配置项由我们提供。它们对应于我们内部支持的各种数据库,现在也以这种方式对外开放。
这些配置可能不能直接用于连接。它们不包含服务器之类的信息,但仍然可以作为创建新配置的基础。下面我们还可以看到其他一些配置。
其中一些是我自己创建的。但大多数并非如此。JMP 会根据 ODBC 管理的连接(称为 Dsns 域名源名称)自动创建它们。我们可以看到这里列出的连接,以及我 Mac 上的 Dsns,其中一些也在 JMP 中显示。
这些连接是自动创建的,这样更容易上手。我这就关闭这个窗口。既然我已经创建了这些连接,那么理想情况下,最简单的操作就是点击连接。
实际上,这样做行不通。我们看到的是驱动程序返回的错误信息,提示我们没有提供用户 ID。JMP 在转换此配置时未能收集到该信息。
不过,这里给了我们一个机会。对话框建议我们创建一个新的配置,这样我们就可以借鉴这个配置了。添加我们需要的信息,比如用户名和密码。然后我们就可以尝试连接了。所以我们点击“是”。
这是连接器编辑器。我们稍后会详细讨论。但现在,我们先添加所需的信息。我们需要一个密码。之前没有密码。现在我们要设置一个密码。我来填写一下。我们还需要用户名。方法相同。
现在我们已经填写完毕,可以尝试测试连接了。可以看到测试成功了。既然连接成功了,在正式连接之前,我们先保存一份副本。这样可以避免以后重复操作的麻烦。这里的配置说明我们已经配置好了连接,我已经保存了。现在可以连接了。
这里列出了一些模式。如果我选择其中一个模式,就会看到一个表列表。我们直接选择“唯一正确的表”——大类表。现在最简单的做法就是打开这个表,所以点击“打开表”按钮,我们就能看到要打开的表了。太好了。
但我们也可以使用查询构建器。我先关闭这个窗口,现在我们可以点击查询构建器按钮。查询构建器打开后,我们会看到和之前一样的界面。
我们可以构建查询语句。我可以继续逐步演示。添加一些列,运行查询,查询完成后,我们就能再次看到表格了。现在表格已经生成,我们也看到一切正常。假设我们再来一遍,对吧?
我们已经保存了一个连接,所以应该可以用它了。现在断开这个连接。我们可以继续了。我们可以找到之前保存的那个连接。我们可以连接上,现在连接成功了,我们又能看到所有内容了。
我们再打开一下表格。既然表格已经打开了,我们可能还想用它做点别的事情。我刚才提到了共享,既可以与同事共享,也可以与 JMP Live 共享。我们先从后者开始,共享到 JMP Live。
我要发布数据表了。表格已经准备好了。点击下一步。我们要把它发布到我的个人空间,现在已经发布了,关闭这个窗口,然后我们打开 JMP Live。
这是我的个人空间,我要刷新一下。现在可以看到表格了,把它拉出来。等它加载完毕,现在如果你进入设置,就可以选择用脚本刷新数据。这就是它与查询构建器的一个区别。以前我们需要连接字符串来设置刷新脚本。现在如果我们直接使用源脚本,就会发现有些不同。
我现在不打算仔细研究这个。我只想看看它能不能运行,所以我先保存一下。我会输入一些凭据,然后继续。我点击刷新。看看它是否有效。失败了。但我们来看看原因。这里出现了一个错误。这有点难理解,但重点是我们没有指定有效的驱动程序。
我们来看看脚本,更详细地分析一下,找出问题所在。我们可以看到这里有一行代码指定了驱动程序是开源数据库。我们在这里指定了一个驱动程序。但是你看,它又是一个仅适用于 Mac 的驱动程序,所以它无法正常工作也就不足为奇了。
之前,我们需要做的就是找出Windows驱动程序的名称,把它替换到这里,然后再试一次。但这次我不需要找出它的名称。我要把它删除。保存后,我们再试一次。看起来成功了,所以我重新加载它。
这里其实没什么特别的。数据本身没有变化,但我们确实看到了刷新后的效果。之所以有效,是因为……我们再来看看脚本。我们使用的是内置配置。我们添加了这些额外的配置项,使其与 JMP 创建的配置相匹配。
一般来说,每当我们发布 JMP 正式版时,我们都会设置源脚本,以便创建与您指定的配置等效的内容。
造成差异的原因在于,我们不直接在 pkg-config 中指定 JMP dev 的 ID,因为 JMP Live 并不识别这个特定的名称。为了使其与 JMP Live 更兼容,我们重新创建了一个等效的配置,首先使用 JMP Live 中已知的一个内置配置,然后在此基础上添加其他所有内容。
这个内置功能让一切正常运行。正如我所说,数据连接器的核心理念之一就是可以进行平台相关的配置。我们可以看到,通过这个内置配置(即Postgres的内置配置),它会自动在运行平台上查找合适的驱动程序。
在我的Mac上,它能找到真正的开源数据库驱动程序;在Windows上,它能找到适用于Windows的Postgres驱动程序。所有内置驱动程序都是如此。
这样也方便了Mac和Windows之间,以及安装了不同驱动程序的机器之间共享文件。这就是JMP的实时运行状态。我们回到JMP,然后就可以关闭这个窗口了。断开连接,一切恢复原状。以上是配置信息,由JMP创建。
现在,如果我们想自己创建一个配置呢?我们不想通过 ODBC 管理器,让 JMP 来获取配置,然后再在这里显示出来。让我们同时看一下,更详细地讨论一下。这次我们连接到 SQL Server。这就是这里的配置。
如果我点击“新建”,它会让我创建一个基于当前配置的新配置,这样我就不必指定 SQL Server 的所有细节。我只需要指定我的连接特有的信息。打开后,您会看到编辑器。现在我们来更详细地看一下。
首先,我们选择连接类型,JMP 版本为 18。这里只有 ODBC。然后是连接的基础配置,正如我所说,我们从内置的 SQL Server 配置开始。可以看到,这里使用的是内置的 SQL Server 配置。具体来说,我们要用它来指定我们需要的功能。当然还有其他选项。我们可以完全从头开始,使用 ODBC 的默认设置。
我们可以指定文件路径。我们甚至可以指定一个配置作为基准。但通常情况下,我们预计您会使用另一个配置,所以这里会用到这个 ID。下面是所有选项,它们被分组显示,第一组是连接信息。
连接目标以及您的凭据。这些信息都包含在 ODBC 连接字符串中。下方还有其他选项,因此我们可以看到各种 SQL 选项,以及仅针对底层 ODBC 层的选项。
如果我点击这里的“连接”,我们实际上需要建立一个连接。接下来我会填写所需的信息。数据库名称是 SQBTest。您可以看到,当我填写完之后,这个复选框就被取消选中了。这表示我们是否正在使用从基本配置中获取的值。
无论我是否修改过,复选框都处于未选中状态。我可以重新选中它,它会恢复到初始值。但我们确实需要它。我打算再次填写一下。
这里我们看到的是 JMP 19 之前的共享驱动程序。我需要做这件事,所以我们快速完成。密码值在这里。我们的服务器,还是 jmpdev2。我们有用户名。看看能不能连接上。连接上了。但在继续之前,我们先考虑一下这种情况。假设我实际上连接的不是 SQL Server,而是与 SQL Server 非常相似但不完全相同的服务器。
区别在于,如果你还记得的话,SQL Server 使用方括号。假设它像 Postgres 一样使用双引号。如果我们深入研究所有这些 SQL 选项,会发现很多不同的设置。但我们先来看看引号类型。你看,它目前被指定为方括号。如果我把它改成双引号,那么就能满足数据库的需求了。
为了方便演示,SQL Server 实际上同时支持方括号和双引号。方括号是它的原生格式,但双引号更常用。因为它两者都支持,所以我们接下来就来看看实际效果。先保存一下。这里要连接我的 SQL Server。连接成功。
在查看现有表之前,我们可以先选择一个类别。例如,如果我们使用查询构建器,就会发现它生成的 SQL 代码反映了我们的选择。
通常情况下,你会期望方括号对应方引号。但现在我们用的是双引号。我们也可以看到这样做是有效的。如果我运行查询,就能得到我们的表格。再次强调,我创建的配置并非完全从零开始,而是基于基本配置。我只需要提供几个选项,现在就建立了一个功能齐全的连接。
我甚至还能对某些行为进行一些调整,使其略有不同。现在我终于完成了所有这些努力。如果我组织中的其他人也想利用这些功能呢?正如我演示的那样,这些连接不仅可以与 JMP Live 共享,还可以与其他平台共享。
为此,我们这里有个红色的小三角菜单。点击它,可以看到共享连接器的选项。我这就把它调出来。您可以在左侧看到我们的配置列表。这里列出的配置不包括内置配置,因为不需要共享这些配置。
如果我们选中配置,它会显示在右侧。我双击了它,但我们还有这些按钮,我可以点击这个按钮来移动或删除它。点击这个按钮可以再次添加它。为了方便共享,我们将创建一个插件。我们将使用 JMP 的添加功能来分发这些配置,并使其易于安装。
但因为它是一个插件,所有插件都需要一个 ID。这就是下面这个框的作用。它用于将默认名称设置为您机器的主机名,子组件名称反转。我的机器地址是 mh382.mmt.com。我们将其反转,得到 com.sas.mmt.mh302。这将是基础配置。由于我只添加了一个配置,所以它将使用该配置的名称。但如果我添加另一个配置,例如,那么它将使用“数据连接器”的名称。
但我们先把它去掉。点击保存。它默认名称是完整的 ID 加上 JMP 插件。但我们不需要这样做。我们可以让它更友好一些,所以我们把它叫做“服务器”。实际上,我们还可以做得更好。我们不必使用这个内置名称。我们把它取消掉。我们来更改名称。例如,假设是“公司”,我们将使用我的用户名。我们不会再次使用这个名称,而是会说明它对我们今年探索大会的意义。
点击保存。我们打算把它改成一个更友好的名字。保存后,系统会询问是否要保留密码。考虑到您可能不想与他人分享密码,我们提供了一个选项,可以帮助您自动删除密码。在这种情况下,我们就删除密码吧。
你可以看到它已经保存了。我的桌面现在有了这个插件。但是现在我们该怎么用它呢?嗯,你得把它给别人。不过这次,我不打算给别人,而是给自己用。我们切换到Windows系统。我们得快速登录一下,好了。这是JMP。我们需要找到这个插件,我的下载文件夹在这里。现在我找到了这个插件,打开JMP,安装它。
好了,现在我们来看看实际操作。依次选择“文件”、“数据库”、“数据连接器”。我们打开配置界面。可以看到,配置在这里。尝试连接。连接失败,因为登录失败。这很正常,我们之前更改了密码。假设我们想进一步配置,那就把密码添加回去。你可以测试一下。可以看到连接成功了。点击“确定”。可以看到连接成功了。
我们已经创建了一个 Mac 实例(听不清 00:26:10)。我们把它迁移到了 Windows 系统,并且能够连接。我们会看到所有让这一切正常运行的配置都是一样的。这就是共享。这就是从头开始的配置。但这一切底层是如何运作的呢?让我们回到 JMP。我们在 SQL Server 内置配置下看到了这些。我们还看到了我们创建的其他配置。
它们长什么样?它们放在哪里?内置配置位于 JMP 安装目录下的一个文件夹中,而您创建的配置则会与您的其他数据一起放在 JMP 的用户数据区域中。在 Mac 上,我导航到用户文件夹中的库文件夹;在 Windows 上,则转到“应用程序支持”和“JMP”。
这是 App Data 目录下的一个文件夹。可以看到,除了许多其他 JMP 特有的信息外,我们还有一些版本相关的文件,比如 Python 相关文件,以及一个数据连接器文件夹。
打开这个文件夹,可以看到所有我配置的文件,以及系统通过 ODBC 为我创建的 JMP 文件。例如,我们可以看到这个 MySQL 服务器配置,以及一个 JMP DC 扩展名,它代表 JMP 数据连接器。除了这些 JMP DC 文件之外,还有一个 JMPDataConnectorRegistry.JSON 文件。它包含了所有这些信息,例如,它将 MySQL 服务器的名称映射到这个特定的文件。
它也可能包含其他信息。但我们来看看里面是什么。我们现在要用一个文本编辑器,抱歉,刚才那个编辑器不对。我提到了两个非常相似的编辑器,所以我们打开这个。我们看到这里有很多看起来像 JSL 的文本,那是因为它就是 JSL,或者更确切地说,它是 JSL 的一个子集。
这里,左边是选项名称,右边是它们的值。第一行很特别,它告诉我们,我们的基准服务器将由 com.JMP.SQLServer 标识。我们可以看到其中有一些设置。我们可以看到,我们设置的这个服务器是他们的数据库,这是我们对专业版的修改。
一般来说,左侧的这些选项名称与编辑器中的内容非常接近。右侧的值也与编辑器中的值类似。这里没有末尾的示例文字。更值得注意的是,用户名和密码这里使用的是编码字符串。我们这样存储它们是为了避免直接存储您的用户名和密码。
但 JMP 仍然能够连接到它们,正如我所说,这就是 JSL。我们可以看到,如果我们想要添加平台特定的配置,就像我们之前看到的内置配置那样。但如果我们想自己进行配置,比如说我们想采用一个我们之前没有讨论过的选项:块获取。启用块获取可以提高数据获取效率,但有时它不受支持或无法正常工作。
假设它在我的 Mac 上可以正常工作,但在 Windows 上不行。我们希望它在 Windows 和 Mac 上启用,但在其他情况下禁用。像这样将“阻止获取”选项设置为这个 JSL 表达式的代码行就能达到预期效果,因为右侧的所有值都只是 JSL 代码。
每当 JMP 加载此配置时,它都会进行评估。它会显示“哦,是的”,在这种情况下,我们使用的是 Mac。我们将启用块获取。这就是它的工作原理。是的,JMP 本身可以使用 JSL 来处理这些。我们关闭此窗口,因为它已不再重要。
咱们就此结束吧。回到 JMP 编辑器。打开一个脚本编辑器。这是个样板代码。我能做什么呢?我可以从文件中加载配置。它将使用内存数据连接器。我们再来看看……我们一直在使用这个 MySQL 服务器。这行代码会加载它,并提供配置信息。然后我可以做一些事情,比如从中获取特定值,例如我们设置的“阻止获取”选项。
或者我可以获取引用类型。我可以更改选项,所以我可以将引用类型设置回之前的值,也就是括号。我可以关闭“块提取”功能。现在我们可以再次打印,看看它是否达到了我们想要的效果。如果我运行所有这些操作,我们会看到“块提取”功能开启,引用类型为双精度浮点数。然后,在我设置之后,一切都关闭了。
这就是你可以用来操控它的一些方法。如果我们查看整个系统,就会发现所有值都不是默认值。例如,我们可以看到用户名和密码。但我们还会看到许多其他选项,其中 SQL Server 的设置也与默认值不同。所有这些都在注册表中。这种从名称到实际配置的映射也可以通过 JSL 访问。
这里我有一个变量。然后我可以执行一些操作,比如获取所有可用条目。这将列出我们创建的条目以及 JMP 内置的条目。如果我们在 Windows 系统上执行此操作,我们还会看到通过插件安装的条目。我们可以获取特定条目的元数据。我们可以再次查看我们在这里创建的配置。这将告诉我们名称和路径。这些是基本信息,但它还包括类型,并且由于它是 ODBC 连接,因此还会包含驱动程序。
您还可以为 JSL 注册配置。假设我们要编写自己的配置,并将其命名为 MySQLServer2DC。我们添加了一个新的路径变量。熟悉路径变量的朋友应该知道,这个变量指向我之前展示的那个数据连接器文件夹。我可以在那里写入一些文本。
我们尽量简化操作。首先,配置一下这个 MySQL 服务器。然后,把一些类型设置恢复到原来的状态。现在我这里有一些配置。最后,我会按照我的路径注册它。名称要和文件名匹配,就像我们之前对其他文件做的那样。然后是路径。路径。如果我运行所有这些命令,我们就可以尝试加载它了。
接下来我们继续之前的操作,但这次要用到这两个对象。我们可以看到它的工作方式,它会在这里打印出一些内容。我们甚至可以获取我们修改的值。可以看到它在那里。好的,所以我们再次看到了这一点,我们都可以使用 JSL 来操作配置。如果我们愿意直接操作这些配置,我们可以查看它们在文件系统中的位置,并且可以添加平台特定的配置。
我刚才讲了很多内容。我们来总结一下。回到开头。我说过,我们为这个项目设定了具体的目标。好,那我们逐一来看。第一个目标是能够连接到更多数据源。在 JMP 18 中,我们扩展了 ODBC 的数据源访问范围。我希望通过例如更改 SQL Server 的 JSON 类型,能让大家初步了解一下这方面的可能性。
我们增强了与数据源的兼容性。关于共享,我希望通过展示 JMP Live to Windows 的共享功能,能够清楚地说明我们在这方面的能力。最后,我们实现了更统一的交互方式。这是我们之前从未实现过的。我向您展示了一个全新的界面,也展示了一些仅适用于 ODBC 的功能。需要注意的是,我们目前专注于 ODBC,并且正在为其他功能打基础。这些功能我们将在未来推出。
谈到 JMP 18.1 的未来发展方向,我们计划进行一些小的改进,主要针对编辑器。JMP 19 将会对编辑器进行更多增强。但我认为更重要的是,我们将推出新的连接类型。我们将把目前仅限于 ODBC 的连接方式扩展到其他类型。我想首先提到的就是 SAS。
在 JMP 18 中,我们不得不移除 SAS 连接功能。但在 JMP 19 中,我们将重新引入该功能,并将其集成到数据连接器框架中。这意味着连接界面、配置编辑器以及共享配置的功能(例如通过插件)都将保持不变。此外,我们还将添加对 Amazon S3 和 Microsoft SharePoint 的连接。我认为这是用户期待已久的功能。
有趣的是,S3 和 SharePoint 这两个产品不会随 JMP 一起分发。而 SAS,我们的目标是使其功能类似于 JMP 18 之前的版本。它将随 JMP 一起分发。您将可以访问许多以前提供的 GSL 功能。
对于 S3 和 SharePoint,它们不会与 JMP 打包在一起,而是通过 JMP Marketplace 分发。你们当中有些人可能听说过 JMP Marketplace。如果你们还没听说过,你们很可能会在其他探索环节中了解到它。
简而言之,这将是向 JMP 分发扩展程序的一种方式。我们将通过这种方式分发 S3 和 SharePoint 连接功能。为了使这些扩展程序能够与 JMP 协同工作,我们将定义一个从 JMP 公开的 Python API,该 API 可用于与所有需要集成到该连接器框架中的组件进行交互,进而连接到查询构建器及更高级的功能。
为了实现这些功能,我们使用了该接口,也使用了现有的Python库。这体现了Python生态系统的魅力,也是我们为改进JMP 18的Python集成所做的工作的成果。但这并非我们独有的。
我们将公开这个接口,并编写相关文档,让您不仅了解我们,还能创建新的连接类型,并将它们与 JMP 和查询生成器集成。您可以使用所有相同的工具。
这就是我们未来要做的事情。基本上就是这些了。我想再次强调,我希望我们在2018年所做的工作,不仅为我在这里讨论的这些未来改进奠定了基础,而且本身也为我们利用ODBC所能做的事情提供了强有力的升级。
我们可以连接到更多数据源,而且可以更轻松地共享这些连接。我认为未来我们能做的事情会更多,前景更加光明。我非常期待我们未来能取得的成就。最后,感谢各位的收听,希望你们接下来的探索之旅愉快。