这里写自定义目录标题
背景
某日下班后,领导临时分配了一个任务,有一个https接口提供的csv格式数据,量级比较大,需要提取并落表,解析成结构化的数据,用于做一些数据分析。
业务方提供了几天的接口文件url,格式如下:https://*****file.csv,直接点击即进入浏览器下载状态,一个文件量级达二十多G,预计需要两个小时下载完成;
同时,业务方也提供了一些清洗及指标统计规则,但未提供数据原始字段格式。
尝试用python来解决问题
这个需求很明确,主要困难点在于数据量级非常大,用常规的下载后导入数仓的方式,已无法实现,所以寄希望于脚本工具,期望分批次下载导入数据表。
初步想法是,用司内封装好的notebook来写python脚本,实现脚本化的数据下载及写入。
首先,想到的是用pandas库里的数据处理模块,于是按如下脚本来实现:
python
import pandas as pd
from sqlalchemy import create_engine
# 读取 CSV 文件
url = "https://*****file.csv"
data = pd.read_csv(url)
# 创建数据库连接(请替换为您的数据库连接信息)
db_url = "mysql+pymysql://username:password@host:port/database" # 替换为您的 MySQL 连接信息
engine = create_engine(db_url)
# 将数据写入数据库(请替换为目标表名)
data.to_sql('target_table_name', con=engine, if_exists='replace', index=False)
print("数据成功入库!")
请确保安装了所需的库:
bash
pip install pandas sqlalchemy pymysql
随之,又想到数据量过大,写到mysql可能会存在一些问题,于是想写到hive里。
python
import pandas as pd
from pyhive import hive
# 读取 CSV 文件
url = "https://****file.csv"
data = pd.read_csv(url)
# Hive 连接参数
host = 'your_hive_host'
port = 10000 # Hive 默认端口
username = 'your_username'
database = 'your_database'
# 创建 Hive 连接
conn = hive.Connection(host=host, port=port, username=username, database=database)
# 写入数据到 Hive
table_name = 'your_table_name'
data.to_sql(table_name, con=conn, if_exists='replace', index=False)
print("数据成功入库!")
请将 your_hive_host、your_username、your_database 和 your_table_name 替换为您的具体信息。
注意事项
- 确保 Hive 服务正在运行,并且可以通过提供的连接参数访问。
- Hive 表需要提前创建,或者可以使用
if_exists='replace'创建新表。
接着,还需要创建一个表,用于写入数据,于是需要知道源头数据里的表结构,那么需要提取到数据后,能打印出几行来,这样就能知道源头数据的格式,于是加了一句:
python
import pandas as pd
# 假设 df 是你的 DataFrame
df = pd.read_csv('your_data.csv') # 读取数据
# 查看前十行
print(df.head(10))
以上,本以为问题就轻松解决了,没想到,报了如下错误:
URLError: <urlopen error [Errno 110] Connection timed out>
咨询了AI,得到答案如下:
可能的原因和解决方法包括:
-
网络问题:检查你的网络连接是否正常。
-
URL错误:确认URL地址是否正确。
-
服务器问题:目标服务器可能出现故障或正在维护。
-
防火墙或代理:有可能是防火墙或代理阻止了连接,检查相关设置。
-
超时设置 :可以尝试增加超时时间,例如:
pythonimport urllib.request url = 'http://example.com' response = urllib.request.urlopen(url, timeout=10) # 设置超时为10秒 -
使用其他库 :如果问题持续,可以尝试使用
requests库,它通常更易于处理HTTP请求:pythonimport requests try: response = requests.get(url, timeout=10) response.raise_for_status() # 检查请求是否成功 except requests.exceptions.RequestException as e: print(e)
根据具体情况检查并调整相应的设置。
到这里,以为是由于资源不足导致的,毕竟刚开始运行,并没有做任何特殊的资源配置,而平台对普通python并没有提供资源配置选择的入口,但pyspark可以,于是切换到pyspark的资源,同时考虑了资源配置,脚本如下:
python
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("创建读取任务") \
.config("spark.executor.memory", "16g") \
.config("spark.driver.memory", "16g") \
.config("spark.executor.instances", "8") \
.config("spark.executor.cores", "4") \
.config("spark.sql.shuffle.partitions", "100") \
.config("spark.default.parallelism", "100") \
.config("spark.sql.parquet.compression.codec", "snappy") \
.getOrCreate()
# CSV 文件的 URL,Spark 和 Hadoop 默认不支持通过 `https` 访问文件。
url = "https://****file.csv"
# 读取 CSV 数据
df = spark.read.csv(url, header=True, inferSchema=True)
print("数据成功读取!")
# 显示数据
df.show()
# 关闭 Spark 会话
spark.stop()
配置参数说明:
spark.executor.memory:每个 executor 分配的内存大小。spark.driver.memory:Driver 程序使用的内存。spark.executor.instances:启动的 executor 数量。spark.executor.cores:每个 executor 使用的 CPU 核心数。spark.sql.shuffle.partitions:Shuffle 操作时使用的分区数,通常设置为较高值以提高并行度。spark.default.parallelism:默认的并行度,用于某些操作的并行化。spark.sql.parquet.compression.codec:指定 Parquet 文件的压缩方式,snappy是一种常用的高效压缩格式。
根据实际集群的资源情况和数据特点,适当调整这些参数。
依然读取报错,
TimeoutError: [Errno 110] Connection timed out
这时AI对报错的解释有所不同:
这个错误是由于 Apache Spark 无法识别 `https` 协议的文件系统。Spark 和 Hadoop 默认不支持通过 `https` 访问文件。
解决方法:
1. **使用 `hdfs` 或 `file` 协议**:如果可能,尝试将文件移动到 HDFS 或本地文件系统中。
2. **添加支持**:如果需要通过 `https` 访问,可以尝试添加相应的 Hadoop 依赖,例如 `hadoop-aws`,并配置 AWS S3 等存储。
3. **配置 Spark**:确保在 Spark 的配置中正确设置了相关的文件系统类,例如在 `spark-defaults.conf` 中添加:
```plaintext
spark.hadoop.fs.azure.NativeAzureFileSystem
4. **检查 URL**:确保提供的 URL 是有效的,并且服务器允许访问。
根据具体使用环境选择合适的方法进行调整。
于是,又切换回普通的python来运行,并且寄希望于在脚本里配置资源分配:
python
要从 HTTPS 接口提取 100GB 的 CSV 数据,可以使用 Python 的 `requests` 库和 `pandas` 库。以下是一个基本的示例,展示了如何逐步下载和保存大文件:
```python
import requests
import pandas as pd
url = 'https://example.com/largefile.csv' # 替换为实际的 URL
chunk_size = 1024 * 1024 # 每次下载 1MB
# 创建一个空的 DataFrame,用于存储数据
df = pd.DataFrame()
# 逐块下载数据
with requests.get(url, stream=True) as response:
response.raise_for_status() # 检查请求是否成功
for chunk in response.iter_content(chunk_size=chunk_size):
# 将每个块解码为字符串,然后再转换为 DataFrame
chunk_data = pd.read_csv(pd.compat.StringIO(chunk.decode('utf-8')), header=None)
df = pd.concat([df, chunk_data], ignore_index=True)
# 保存为 CSV 文件
df.to_csv('largefile.csv', index=False)
注意事项:
1. 确保服务器允许大文件下载。
2. 根据实际情况调整 `chunk_size` 以优化内存使用。
3. 处理 CSV 解析时,确保数据格式正确。
4. 如果 CSV 数据过大,考虑直接写入文件而不是加载到内存中。
此时的报错更明确了,依然是连接失败:
python
MaxRetryError: HTTPSConnectionPool(host='*****.com', port=***): Max retries exceeded with url: ***file.csv (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at ***>, 'Connection to *****.com timed out. (connect timeout=None)'))
AI对此的解释是:
这个报错表示在尝试连接到指定的 HTTPS 服务器时,连接超时。可能的原因包括:
- 网络问题:无法访问互联网或目标服务器。
- 服务器故障:目标服务器可能已关闭或出现故障。
- 防火墙设置:防火墙可能阻止了该连接。
- URL 错误 :提供的 URL 可能不正确。
建议检查网络连接,确认服务器是否在线,并验证 URL 的正确性。
至此,放弃用python来从该接口提取数据,考虑用其他方式。
非python方式解决
python
要快速从 HTTPS 接口提取 25GB 的大文件,可以考虑以下方法:
1. **分块下载**:
- 使用 `Range` 请求头分块下载文件。可以将文件分成多个部分并并行下载,然后在本地合并。
2. **多线程/多进程下载**:
- 使用库(如 `requests` 和 `concurrent.futures`)创建多个线程或进程同时下载不同部分。
3. **使用专门的下载工具**:
- 使用 `wget` 或 `curl` 等工具,支持断点续传和多线程下载。
4. **优化网络设置**:
- 确保带宽没有被其他应用占用,使用有线连接而不是无线连接。
5. **检查服务器限制**:
- 确保服务器允许大文件下载,检查是否有速率限制或并发连接限制。
6. **使用 CDN**:
- 如果可能,使用内容分发网络 (CDN) 来提高下载速度。
示例代码(使用 `requests` 和分块下载):
```python
import requests
url = 'https://example.com/largefile'
response = requests.head(url)
file_size = int(response.headers['Content-Length'])
chunk_size = 1024 * 1024 # 1 MB
num_chunks = (file_size // chunk_size) + 1
with open('largefile', 'wb') as f:
for i in range(num_chunks):
headers = {'Range': f'bytes={i * chunk_size}-{(i + 1) * chunk_size - 1}'}
chunk = requests.get(url, headers=headers)
f.write(chunk.content)
根据具体情况调整参数和方法。
但,这个方案同样会遇到连接不上接口服务器的问题,所以放弃读取接口服务器。
发现,已经通过浏览器下载成功了一个csv文件,只是量级特别大,无法通过常规方式入数据库,所以接下来,只需要解决如何该大数据,写到表里。
如何用python读取本地文件,再写入到hive表中?
要将本地文件读取并写入到 Hive 表中,可以使用 PyHive 库或类似的库。以下是一个简单的示例,展示如何使用 Pandas 和 PyHive 将 CSV 文件读取到 Hive 表中。
首先,确保安装了必要的库:
bash
pip install pandas pyhive
然后,可以使用以下代码:
python
import pandas as pd
from pyhive import hive
# 读取本地文件
file_path = 'path/to/your/file.csv'
df = pd.read_csv(file_path)
# 连接到 Hive
conn = hive.Connection(host='your_hive_host', port=10000, username='your_username')
cursor = conn.cursor()
# 创建 Hive 表(如果尚未创建)
create_table_query = """
CREATE TABLE IF NOT EXISTS your_table_name (
column1 STRING,
column2 INT,
...
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE
"""
cursor.execute(create_table_query)
# 将数据写入 Hive 表
for index, row in df.iterrows():
insert_query = f"""
INSERT INTO your_table_name (column1, column2, ...)
VALUES ('{row['column1']}', {row['column2']}, ...)
"""
cursor.execute(insert_query)
# 关闭连接
cursor.close()
conn.close()
说明:
1. 替换 `file_path`、`your_hive_host`、`your_username`、`your_table_name` 和列名以符合你的实际情况。
2. 确保 Hive 表的结构与 CSV 文件的结构相匹配。
3. 如果数据量大,建议使用批量插入或更高效的方法。
最终解决方案
在寻找hive数据库的连接信息时,突然想到,为啥不直接舍弃python?
用终端命令行的方式,将大文件拆分为n个小文件,一个个小文件导入hive表中,如此简单直接,只是无法例行化了。
1、找到mac文件的文件url:
- 打开Finder,找到文件或文件夹。
- 右键点击文件或文件夹,选择"显示简介",在弹出的信息窗口中可以看到路径,选择并复制该路径,能得到具体的url。
2、打开电脑自带的终端,输入:
bash
split -b 380m /Users/****file.csv newfile_prefix_
3、开始执行后,就能在该文件链路里查到n个以"newfile_prefix_"开头的小文件了,其中380m,是根据导入文件限制,自行设置的小文件大小。
在进行实际导入前,还需要手动给每个小文件,加上文件后缀,比如csv、txt等,重命名文件名就可以实现。