作者:来自 Elastic Quentin Pradet
自 Elasticsearch 8.15 或 Elasticsearch Serverless 以来,ES|QL 响应支持 Apache Arrow 流式传输格式。这篇博文将向你展示如何在 Python 中利用它。在之前的一篇博文中,我演示了如何使用 CSV 作为中间表示将 ES|QL 查询转换为 Pandas 数据帧。不幸的是,CSV 需要显式类型声明,速度很慢(尤其是对于较大的数据集),并且不处理嵌套数组和对象。Apache Arrow 消除了所有这些限制。
ES|QL 到 Python 中的 Pandas 数据帧
导入测试数据
首先,让我们导入一些测试数据。和以前一样,我们将使用 employees 样本数据和映射。加载此数据集的最简单方法是在 Kibana 控制台中运行这两个 Elasticsearch API 请求。
将数据集转换为 Pandas DataFrame 对象
好的,解决了这个问题后,让我们使用 ES|QL Arrow 导出将完整的 employees 数据集转换为 Pandas DataFrame 对象:
from elasticsearch import Elasticsearch
client = Elasticsearch(
"https://[host].elastic-cloud.com",
api_key="...",
)
response = client.esql.query(
query="FROM employees | DROP is_rehired,job_positions,salary_change* | LIMIT 500",
format="arrow",
)
df = response.to_pandas()
print(df)
尽管此数据集仅包含 100 条记录,但我们仍使用 LIMIT 命令来避免 ES|QL 警告我们可能缺少记录。这将打印以下数据框:
avg_worked_seconds birth_date emp_no ... last_name salary still_hired
0 268728049 1953-09-02 10001 ... Facello 57305 True
1 328922887 1964-06-02 10002 ... Simmel 56371 True
2 200296405 1959-12-03 10003 ... Bamford 61805 False
3 311267831 1954-05-01 10004 ... Koblick 36174 True
4 244294991 1955-01-21 10005 ... Maliniak 63528 True
.. ... ... ... ... ... ... ...
95 204381503 1954-09-16 10096 ... Mandell 43889 False
96 206258084 1952-02-27 10097 ... Waschkowski 71165 False
97 272392146 1961-09-23 10098 ... Servieres 44817 False
98 377713748 1956-05-25 10099 ... Sullins 73578 True
99 223910853 1953-04-21 10100 ... Haraldson 68431 True
[100 rows x 17 columns]
好的,那么这里到底发生了什么?
- 给定 format=”arrow”,Elasticsearch 返回二进制 Arrow 流数据
- Elasticsearch Python 客户端查看 Content-Type header 并创建 PyArrow 对象
- 最后,PyArrow 的 Pandas 集成将 PyArrow 对象转换为 Pandas 数据帧。(请注意,在大多数情况下,这不是零拷贝转换。)
这意味着要使此示例正常工作,需要安装 Pandas 和 PyArrow 可选依赖项。请注意,Pandas 本身不是严格必需的,只有 PyArrow 是必需的。如果你想改用 Polars,可以使用 from_arrow 从客户端返回的 PyArrow 表中创建 Polars 数据框。
一个限制是 Elasticsearch 目前不处理多值字段,这就是我们不得不删除 is_rehired、job_positions 和 salary_change 列的原因。此限制将在 Elasticsearch 的未来版本中取消。
无论如何,你现在有一个 Pandas 数据帧,你可以使用它来进一步分析数据。但是你也可以继续使用 ES|QL 处理数据,这在查询返回超过 10,000 行(ES|QL 查询当前可以返回的最大行数)时特别有用。
更复杂的查询
在下一个示例中,我们使用 STATS … BY(与 SQL 中的 GROUP BY 类似)计算有多少员工讲某种语言。然后我们使用 SORT 对 languages 列的结果进行排序:
response = client.esql.query(
query="""
FROM employees
| DROP is_rehired,job_positions,salary_change*
| STATS count = COUNT(emp_no) BY languages
| SORT languages
| LIMIT 500
""",
format="arrow",
)
df = response.to_pandas()
print(df)
与 CSV 不同,我们不必指定任何类型,因为 Arrow 数据已经包含类型。结果如下:
count languages
0 15 1.0
1 19 2.0
2 17 3.0
3 18 4.0
4 21 5.0
5 10 NaN
21 名员工讲 5 种语言,哇!
带参数的查询
最后,假设你想要扩展上一节中的查询以仅考虑会说 N 种或更多语言的员工,其中 N 是可变参数。为此,我们可以使用 ES|QL 内置的参数支持,这消除了手动组装带有可变部分的查询所带来的注入攻击风险:
response = client.esql.query(
query="""
FROM employees
| DROP is_rehired,job_positions,salary_change*
| STATS count = COUNT(emp_no) BY languages
| WHERE languages >= (?)
| SORT languages
| LIMIT 500
""",
format="arrow",
params=[3],
)
df = response.to_pandas()
print(df)
打印内容如下:
count languages
0 17 3
1 18 4
2 21 5
结论
正如我们所见,ES|QL 的原生 Arrow 支持使得使用 Pandas 和其他 DataFrame 库比使用 CSV 更加方便,并且随着时间的推移,它将不断改进,未来版本的 Elasticsearch 将提供多值支持。
其他资源
如果你想了解有关 ES|QL 的更多信息,ES|QL 文档是最好的起点。你还可以查看使用波士顿凯尔特人队数据的其他 Python 示例。要了解有关 Python Elasticsearch 客户端本身的更多信息,你可以参考文档,在讨论中使用 language-clients 标签提问,或者在发现错误或有功能请求时提交新问题。谢谢!
准备好自己尝试一下了吗?开始免费试用。
Elasticsearch 集成了 LangChain、Cohere 等工具。加入我们的高级语义搜索网络研讨会,构建你的下一个 GenAI 应用程序!
原文:From ES|QL to native Pandas dataframes in Python — Search Labs