当前位置:   article > 正文

如何执行混合查询?

如何执行混合查询?

图片

本文字数:9866;估计阅读时间:25 分钟

作者:Mark Needham

审校:庄晓东(魏庄)

本文在公众号【ClickHouseInc】首发

在我意识到:人们用ClickHouse的大部分时间里,我们理解它是一个带有传统客户端-服务器架构的分析数据库,旨在以低延迟为高并发查询提供服务。

直到最近几个月,我才被这样几个工具改变了我的理解:ClickHouse Local,它允许我们通过CLI运行ClickHouse前端的进程内版本,以及chDB,一个由ClickHouse驱动的嵌入式SQL OLAP引擎。

在为ClickHouse YouTube频道录制的大多数视频中,我发现自己在混合使用这些工具。

最值得注意的例外是那段视频,其中通过ClickPy解释了Materialized Views。ClickPy是一个托管在ClickHouse Cloud上的ClickHouse服务,包含有关从Python的PyPi包管理器下载软件包的数据。该数据集帮助我们了解长期以来最受欢迎的软件包,按国家、安装程序、版本和许多其他维度分组。

数据库还包含有关每个软件包的元数据,包括项目主页,通常是GitHub代码库。这让我想到,将这些库的GitHub指标(例如星标数或分叉数)与下载数进行比较可能会很有趣。

我询问了我的同事戴尔,是否可以将GitHub数据添加到ClickPy服务器上,他建议我首先查看ClickHouse的remote和remoteSecure表函数。这些函数允许您从另一个ClickHouse客户端动态查询远程ClickHouse服务器。我们还可以将远程查询的数据与本地ClickHouse中的数据进行连接(join),当与ClickHouse Local一起使用时,我们可以实现一种混合查询。

我应该指出,这不是当前ClickHouse的优化用例,但我认为这将是一个有趣的实验,所以让我们开始吧!

使用ClickHouse Local查询GitHub指标

我先编写了一个小Python脚本,从GitHub API下载尽可能多的项目的数据,将每个项目存储在自己的机器上的一个JSON文件中。例如,以下是Langchain项目数据的子集:

  1. {
  2. "id": 552661142,
  3. "node_id": "R_kgDOIPDwlg",
  4. "name": "langchain",
  5. "full_name": "langchain-ai/langchain",
  6. ...
  7. "topics": [],
  8. "visibility": "public",
  9. "forks": 10190,
  10. "open_issues": 2109,
  11. "watchers": 69585,
  12. "default_branch": "master",
  13. ...
  14. "subscribers_count": 606
  15. }

我们将使用ClickHouse Local探索这些文件,让我们在本地的机器上启动它:

./clickhouse local -m

我们可以运行以下查询来查找根据GitHub星标最受欢迎的PyPi软件包:

  1. FROM file('data/*.json', JSONEachRow)
  2. SELECT full_name, stargazers_count AS stars, forks
  3. ORDER BY stargazers_count DESC
  4. LIMIT 10;
  5. ┌─full_name────────────────┬──stars─┬─forks─┐
  6. │ huggingface/transformers │ 11607323147
  7. │ langchain-ai/langchain │ 6958510190
  8. │ tiangolo/fastapi │ 652105519
  9. │ yt-dlp/yt-dlp │ 609144994
  10. │ keras-team/keras │ 5983619477
  11. │ ansible/ansible │ 5935223867
  12. │ openai/whisper │ 512175828
  13. │ localstack/localstack │ 503013822
  14. │ Textualize/rich │ 455821686
  15. │ psf/black │ 355452339
  16. └──────────────────────────┴────────┴───────┘
  17. 10 rows in set. Elapsed: 0.140 sec. Processed 2.08 thousand rows, 14.97 MB (14.91 thousand rows/s., 107.28 MB/s.)
  18. Peak memory usage: 48.50 KiB.

我想看到在GitHub上受欢迎的生成式AI应用程序中使用的许多库,这并不太令人惊讶。

在ClickHouse Cloud上查询受欢迎的PyPi项目

现在,我们需要确定ClickPy数据库中的哪些项目的项目主页是GitHub仓库。让我们首先使用只读的play用户连接到ClickPy数据库:

  1. ./clickhouse client -m \
  2. -h clickpy-clickhouse.clickhouse.com \
  3. --user play --secure

现在让我们编写一个查询,找出具有GitHub仓库的最受欢迎的PyPi项目。我们将通过连接pypi_downloadsprojects表来实现这一点。我们直接在服务器上运行以下内容:

  1. SELECT name,
  2. replaceOne(home_page, 'https://github.com/', '') AS repository,
  3. sum(count) AS count
  4. FROM pypi.pypi_downloads AS downloads
  5. INNER JOIN (
  6. SELECT name, argMax(home_page, version) AS home_page
  7. FROM pypi.projects
  8. GROUP BY name
  9. ) AS projects ON projects.name = downloads.project
  10. WHERE projects.home_page LIKE '%github%'
  11. GROUP BY ALL
  12. ORDER BY count DESC
  13. LIMIT 10;
  14. ┌─name───────────────┬─repository─────────────────┬───────count─┐
  15. │ boto3 │ boto/boto316031894410
  16. │ botocore │ boto/botocore │ 11033306159
  17. │ certifi │ certifi/python-certifi │ 8606959885
  18. │ s3transfer │ boto/s3transfer │ 8575775398
  19. │ python-dateutil │ dateutil/dateutil │ 8144178765
  20. │ charset-normalizer │ Ousret/charset_normalizer │ 5891178066
  21. │ jmespath │ jmespath/jmespath.py │ 5405618311
  22. │ pyasn1 │ pyasn1/pyasn15378303214
  23. │ google-api-core │ googleapis/python-api-core │ 5022394699
  24. │ importlib-metadata │ python/importlib_metadata │ 4353215364
  25. └────────────────────┴────────────────────────────┴─────────────┘
  26. 10 rows in set. Elapsed: 0.260 sec. Processed 12.28 million rows, 935.69 MB (47.16 million rows/s., 3.59 GB/s.)
  27. Peak memory usage: 1.02 GiB.

让我们看一个显示不同数据位于何处的图表。

图片

配置远程查询的权限

接下来我想要做的是:将查找PyPi项目的查询,与返回GitHub指标的查询合并起来。主要的挑战是PyPi数据存储在Clickhouse Cloud上,而GitHub指标存储在我本地的机器上。

我不想用我的GitHub数据污染ClickHouse Cloud实例,所以我将使用remoteSecure表函数从我的机器查询ClickHouse Cloud。为了使用这个函数来连接projectspypi_downloads表,我们需要创建一个具有以下权限的用户:

GRANT CREATE TEMPORARY TABLE, REMOTE ON *.* TO <user>

一旦我在ClickPy服务器上创建了一个名为_mark_的用户,并给予了这个权限,我们就可以回到我们的ClickHouse Local会话,并将密码定义为一个参数:

set param_password = 'my-password';

从ClickHouse Local查询ClickHouse Cloud

现在我们将运行以上查询的一个版本,使用remoteSecure函数找到最受欢迎的PyPi项目。

  1. SELECT name,
  2. replaceOne(home_page, 'https://github.com/', '') AS repository,
  3. sum(count) AS count
  4. FROM remoteSecure(
  5. 'clickpy-clickhouse.clickhouse.com',
  6. 'pypi.pypi_downloads',
  7. 'mark', {password:String}
  8. ) AS pypi_downloads
  9. INNER JOIN
  10. (
  11. SELECT name, argMax(home_page, version) AS home_page
  12. FROM remoteSecure(
  13. 'clickpy-clickhouse.clickhouse.com',
  14. 'pypi.projects',
  15. 'mark', {password:String}
  16. )
  17. GROUP BY name
  18. ) AS projects ON projects.name = pypi_downloads.project
  19. WHERE projects.home_page LIKE '%github%'
  20. GROUP BY ALL
  21. ORDER BY count DESC
  22. LIMIT 10;
  23. ┌─name───────────────┬─repository─────────────────┬───────count─┐
  24. │ boto3 │ boto/boto316031894410
  25. │ botocore │ boto/botocore │ 11033306159
  26. │ certifi │ certifi/python-certifi │ 8606959885
  27. │ s3transfer │ boto/s3transfer │ 8575775398
  28. │ python-dateutil │ dateutil/dateutil │ 8144178765
  29. │ charset-normalizer │ Ousret/charset_normalizer │ 5891178066
  30. │ jmespath │ jmespath/jmespath.py │ 5405618311
  31. │ pyasn1 │ pyasn1/pyasn15378303214
  32. │ google-api-core │ googleapis/python-api-core │ 5022394699
  33. │ importlib-metadata │ python/importlib_metadata │ 4353215364
  34. └────────────────────┴────────────────────────────┴─────────────┘
  35. 10 rows in set. Elapsed: 1.703 sec.

正如我们所期望的那样,我们得到了与之前相同的结果。这个查询运行时间较长,因为虽然JOIN是在ClickPy服务器上完成的,但我们每次运行查询时都会初始化到ClickPy服务器的新连接。我们可以通过在查询前加上EXPLAIN PLAN来检查连接是否是远程完成的,这将返回以下内容:

  1. ┌─explain───────────────────────────────────┐
  2. │ ReadFromRemote (Read from remote replica) │
  3. └───────────────────────────────────────────┘

如果JOIN是在本地执行的,我们将在查询计划中看到Join操作符。

将来自ClickHouse Cloud和ClickHouse Local的数据进行连接(Join)

接下来,让我们将这些数据与本地GitHub数据集进行连接(join):

  1. SELECT
  2. projects.name,
  3. replaceOne(home_page, 'https://github.com/', '') AS repository,
  4. sum(count) AS count,
  5. gh.stargazers_count AS stars
  6. FROM remoteSecure(
  7. 'clickpy-clickhouse.clickhouse.com',
  8. 'pypi.pypi_downloads',
  9. 'mark', {password:String}
  10. ) AS pypi_downloads
  11. INNER JOIN
  12. (
  13. SELECT name, argMax(home_page, version) AS home_page
  14. FROM remoteSecure(
  15. 'clickpy-clickhouse.clickhouse.com',
  16. 'pypi.projects',
  17. 'mark', {password:String}
  18. )
  19. GROUP BY name
  20. ) AS projects ON projects.name = pypi_downloads.project
  21. INNER JOIN
  22. (
  23. SELECT *
  24. FROM file('data/*.json', JSONEachRow)
  25. ) AS gh ON gh.svn_url = projects.home_page
  26. GROUP BY ALL
  27. ORDER BY stars DESC
  28. LIMIT 10;

这产生了以下输出:

  1. ┌─projects.name────────────┬─repository───────────────┬─────count─┬──stars─┐
  2. │ in-transformers │ huggingface/transformers │ 881116073
  3. │ richads-transformers │ huggingface/transformers │ 1323116073
  4. │ transformers-machinify │ huggingface/transformers │ 999116073
  5. │ transformers-phobert │ huggingface/transformers │ 4550116073
  6. │ transformers │ huggingface/transformers │ 302008339116073
  7. │ langchain │ langchain-ai/langchain │ 3565760769585
  8. │ langchain-by-johnsnowlabs│ langchain-ai/langchain │ 56569585
  9. │ langchain-core │ langchain-ai/langchain │ 244092169585
  10. │ gigachain-core │ langchain-ai/langchain │ 418169585
  11. │ langchain-community │ langchain-ai/langchain │ 143815969585
  12. │ gigachain-community │ langchain-ai/langchain │ 191469585
  13. │ yt-dlp-custom │ yt-dlp/yt-dlp │ 94860914
  14. │ yt-dlp │ yt-dlp/yt-dlp │ 8617549560914
  15. │ keras │ keras-team/keras │ 37442430859836
  16. │ keras-nightly │ keras-team/keras │ 2034902959836
  17. │ symai-whisper │ openai/whisper │ 79051217
  18. test10101010101 │ openai/whisper │ 4651217
  19. │ whisper-openai │ openai/whisper │ 1148651217
  20. │ openai-whisper │ openai/whisper │ 202910651217
  21. │ localstack │ localstack/localstack │ 399835350301
  22. └──────────────────────────┴──────────────────────────┴───────────┴────────┘
  23. 20 rows in set. Elapsed: 3.704 sec. Processed 12.28 million rows, 950.66 MB (3.31 million rows/s., 256.66 MB/s.)
  24. Peak memory usage: 339.80 MiB.

huggingface/transformerslangchain-ai/langchainopenai/whisper重复出现多次。这是因为有不同的PyPi项目使用相同的GitHub存储库作为它们的主页。其中一些看起来像是真正不同的项目,但其他一些似乎是主项目的废弃分支。

这个查询运行时间接近4秒,因为在执行与GitHub数据的连接之前,正在将projects和pypi_downloads表的连接结果流式传输到我的ClickHouse Local实例。我们可以看到下面的图表显示了这是如何工作的:

图片

除了keras和transformers,大多数下载量较大的软件包都没有出现在我们的列表中。我们可以通过将ORDER BY子句更改为按下载次数,而不是星数进行排序,来找出这些软件包有多少星数。我们需要更改以下行:\

ORDER BY stars DESC

改为:

ORDER BY count DESC

如果我们运行具有这个更改的查询,我们将看到以下输出:

  1. ┌─projects.name──────┬─repository─────────────────┬───────count─┬─stars─┐
  2. │ boto3 │ boto/boto3160318944108440
  3. │ botocore │ boto/botocore │ 110333061591352
  4. │ certifi │ certifi/python-certifi │ 8606959885707
  5. │ s3transfer │ boto/s3transfer │ 8575775398189
  6. │ python-dateutil │ dateutil/dateutil │ 81441787652164
  7. │ charset-normalizer │ Ousret/charset_normalizer │ 5891178066448
  8. │ jmespath │ jmespath/jmespath.py │ 54056183111975
  9. │ pyasn1 │ pyasn1/pyasn1537830321418
  10. │ google-api-core │ googleapis/python-api-core │ 502239469998
  11. │ importlib-metadata │ python/importlib_metadata │ 4353215364101
  12. └────────────────────┴────────────────────────────┴─────────────┴───────┘
  13. 10 rows in set. Elapsed: 3.957 sec. Processed 11.96 million rows, 941.07 MB (3.02 million rows/s., 237.81 MB/s.)
  14. Peak memory usage: 336.19 MiB.

大多数这些项目在GitHub上并没有受到太多关注!查询仍然需要4秒,但通过这个查询,我们可以加快速度,因为我们是按照远程表上的字段进行排序的。这意味着我们可以通过远程连接返回的记录数量,如下图所示:

图片

让我们将记录数限制为1,000条,如下面的查询所示:

  1. WITH pypiProjects AS (
  2. SELECT home_page, projects.name, sum(count) AS count
  3. FROM remoteSecure(
  4. 'clickpy-clickhouse.clickhouse.com',
  5. 'pypi.pypi_downloads',
  6. 'mark', {password:String}
  7. ) AS pypi_downloads
  8. INNER JOIN
  9. (
  10. SELECT name, argMax(home_page, version) AS home_page
  11. FROM remoteSecure(
  12. 'clickpy-clickhouse.clickhouse.com',
  13. 'pypi.projects',
  14. 'mark', {password:String}
  15. )
  16. GROUP BY name
  17. ) AS projects ON projects.name = pypi_downloads.project
  18. GROUP BY ALL
  19. ORDER BY count DESC
  20. LIMIT 1000
  21. )
  22. SELECT
  23. name,
  24. replaceOne(home_page, 'https://github.com/', '') AS repository,
  25. count,
  26. gh.stargazers_count AS stars
  27. FROM pypiProjects
  28. INNER JOIN
  29. (
  30. SELECT *
  31. FROM file('data/*.json', JSONEachRow)
  32. ) AS gh ON gh.svn_url = pypiProjects.home_page
  33. GROUP BY ALL
  34. ORDER BY count DESC
  35. LIMIT 10;
  36. ┌─name───────────────┬─repository─────────────────┬───────count─┬─stars─┐
  37. │ boto3 │ boto/boto3160318944108440
  38. │ botocore │ boto/botocore │ 110333061591352
  39. │ certifi │ certifi/python-certifi │ 8606959885707
  40. │ s3transfer │ boto/s3transfer │ 8575775398189
  41. │ python-dateutil │ dateutil/dateutil │ 81441787652164
  42. │ charset-normalizer │ Ousret/charset_normalizer │ 5891178066448
  43. │ jmespath │ jmespath/jmespath.py │ 54056183111975
  44. │ pyasn1 │ pyasn1/pyasn1537830321418
  45. │ google-api-core │ googleapis/python-api-core │ 502239469998
  46. │ importlib-metadata │ python/importlib_metadata │ 4353215364101
  47. └────────────────────┴────────────────────────────┴─────────────┴───────┘
  48. 10 rows in set. Elapsed: 1.758 sec. Processed 2.08 thousand rows, 14.97 MB (1.18 thousand rows/s., 8.51 MB/s.)
  49. Peak memory usage: 448.22 MiB.

这次运行时间不到2秒,因为在执行与GitHub数据的连接之前,我们在将如此多的记录流式传输到ClickHouse Local之前。然而,这并不是一个完美的解决方案,因为如果我们的1,000条记录中有超过990条没有在GitHub数据集中找到匹配项,那么我们可能最终只得到少于10条记录。

总结

目前就是这样。我很好奇你们都有什么看法?你能看到这个功能的真实用例吗?如果是的话,请在评论中或在ClickHouse Slack上告诉我们。

图片

​​联系我们

手机号:13910395701

邮箱:Tracy.Wang@clickhouse.com

满足您所有的在线分析列式数据库管理需求

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/526477
推荐阅读
相关标签
  

闽ICP备14008679号