无法使用 cqlsh 将 UTF-8 数据复制到 ScyllaDB
Cannot COPY UTF-8 data to ScyllaDB with cqlsh
我正在尝试将大型数据集从 Postgresql 复制到 ScyllaDB,它应该与 Cassandra 兼容。
这就是我正在尝试的:
psql <db_name> -c "COPY (SELECT row_number() OVER () as id, * FROM ds.my_data_set LIMIT 20) TO stdout WITH (FORMAT csv, HEADER, DELIMITER ';');" \
| \
CQLSH_HOST=172.17.0.3 cqlsh -e 'COPY test.mytable (id, "Ist Einpöster", [....]) FROM STDIN WITH DELIMITER = $$;$$ AND HEADER = TRUE;'
我收到一个没有堆栈跟踪的模糊错误:
:1:'ascii' codec can't decode byte 0xc3 in position 9: ordinal not in range(128)
我的数据和列名,包括已经在 ScyllaDB 中创建的 table 中的数据和列名,包含带有德语文本的值。它不是 ASCII,但我还没有找到设置编码的地方,而且我看到的所有地方似乎都已经在使用 utf-8
。我也试了this,在1135行附近看到了,在我本地的cqlsh里改了(用vim $(which cqlsh)
),但是没有效果。
我正在使用 cqlsh 5.0.1
,使用 pip 安装。 (奇怪的是 pip install cqlsh==5.0.4
)
我也尝试了 docker image that I used to install ScyllaDB 中的 cqlsh
,它有完全相同的错误。
<更新>
按照建议,我将数据通过管道传输到一个文件:
psql <db_name> -c "COPY (SELECT row_number() OVER (), * FROM ds.my_data_set ds) TO stdout WITH (FORMAT csv, HEADER);" | head -n 1 > test.csv
我将其缩小到第一行 (CSV header)。将其通过管道传输到 cqlsh
使其因相同的错误而哭泣。然后,使用 python3.5 交互式 shell,我这样做了:
>>> with open('test.csv', 'rb') as fp:
... data = fp.read()
>>> data
b'row_number,..... Ist Einp\xc3\xb6ster ........`
我们就是这样,\xc3
真人。是 UTF-8 吗?
>>> data.decode('utf-8')
'row_number,....... Ist Einpöster ........`
是的,是 utf-8
。那么错误是如何发生的呢?
>>> data.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 336: ordinal not in range(128)
同样的错误文本,所以它可能也是 Python,但是没有堆栈跟踪,我不知道这是在哪里发生的,默认编码是 utf-8
。我尝试用 utf-8
覆盖默认值,但没有任何改变。不过,在某处,某些东西正在尝试使用 ASCII 解码流。
这是 server/client 上的 locale
:
LANG=
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8
Slack 上有人建议了这个答案UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)
一旦我在开头添加了 cqlsh.py
中的最后两行,它就解决了解码问题,但同一列被报告为无效并出现另一个错误:
:1:Invalid column name Ist Einpöster
旁注:
此时我对这个测试失去了兴趣,我只是想避免出现未回答的问题,请原谅等待时间。当我尝试将其作为分析引擎与 Spark 结合作为 Tableau 的数据源时,我发现了 "better" 个替代方案,例如 Vertica 和 ClickHouse。 "Better"因为两者都有局限性
更新>
如何完成导入?
我看不出您对此有任何答案。 UTF-8 应该 是默认值。
你试过了吗--encoding
?
文档:https://docs.scylladb.com/getting-started/cqlsh/
如果您在这里没有得到答案,您想在我们的 slack channel 上提问吗?
我会先尝试消除您那里的所有额外复杂性。尝试将几行转储到 CSV 中,然后使用 COPY
将其加载到 Scylla 中
那是什么?
作为参数传入的查询包含列列表,其中包含具有非 ASCII 字符的列。在某些时候,cqlsh
将它们解析为 ascii 而不是 utf-8
,这导致了这个错误。
它是如何修复的?
第一次尝试是在 cqlsh
中添加这两行:
reload(sys)
sys.setdefaultencoding('utf-8')
但这仍然使脚本无法处理该列。
第二次尝试是简单地从文件传递查询。如果你不能,请知道 bash 支持进程替换,所以不要这样:
cqlsh -f path/to/query.cql
你可以
cqlsh -f <(echo "COPY .... FROM STDIN;")
一切都很好,只是它也不起作用。 cqlsh
从提示中将 stdin
理解为 "interactive",而不是通过管道输入。结果是它不导入任何内容。可以只创建一个文件,然后从文件中加载它,但这是一个额外的步骤,可能需要几分钟或几小时,具体取决于数据大小。
值得庆幸的是,POSIX 系统有像'/dev/stdin'这样的虚拟文件,所以上面的命令等同于:
cqlsh -f <(echo "COPY .... FROM '/dev/stdin';")
除了 cqlsh 现在认为您实际上有一个文件,并且它像文件一样读取它,因此您可以通过管道传输数据并感到高兴。
这可能会奏效,但出于某种原因我得到了最后一击:
cqlsh.sql:2:Failed to import 15 rows: InvalidRequest - Error from server: code=2200 [Invalid query] message="Batch too large", will retry later, attempt 4 of 5
我认为 15 行对于分布式存储引擎来说太多了,这很有趣。很可能它又是来自与 unicode 相关的引擎的一些限制,只是一条错误的错误消息。或者我错了。尽管如此,在 Slack 的一些人的大力帮助下,最初的问题得到了回答。
更新:utf8:打印无效的 UTF-8 字符位置
添加新的validate_with_error_position功能
which returns -1 如果数据是有效的 UTF-8 字符串
否则第一个无效的字节位置
特点。该职位被添加到例外
Scylla 中所有 UTF-8 解析错误的消息。
validate_with_error_position分两次完成
通过以保持相同的性能
通常情况下,当字符串有效时。
https://github.com/scylladb/scylla/commit/ffd8c8c505b92a71df7e34d5196c7545f11cb12f
我正在尝试将大型数据集从 Postgresql 复制到 ScyllaDB,它应该与 Cassandra 兼容。
这就是我正在尝试的:
psql <db_name> -c "COPY (SELECT row_number() OVER () as id, * FROM ds.my_data_set LIMIT 20) TO stdout WITH (FORMAT csv, HEADER, DELIMITER ';');" \
| \
CQLSH_HOST=172.17.0.3 cqlsh -e 'COPY test.mytable (id, "Ist Einpöster", [....]) FROM STDIN WITH DELIMITER = $$;$$ AND HEADER = TRUE;'
我收到一个没有堆栈跟踪的模糊错误:
:1:'ascii' codec can't decode byte 0xc3 in position 9: ordinal not in range(128)
我的数据和列名,包括已经在 ScyllaDB 中创建的 table 中的数据和列名,包含带有德语文本的值。它不是 ASCII,但我还没有找到设置编码的地方,而且我看到的所有地方似乎都已经在使用 utf-8
。我也试了this,在1135行附近看到了,在我本地的cqlsh里改了(用vim $(which cqlsh)
),但是没有效果。
我正在使用 cqlsh 5.0.1
,使用 pip 安装。 (奇怪的是 pip install cqlsh==5.0.4
)
我也尝试了 docker image that I used to install ScyllaDB 中的 cqlsh
,它有完全相同的错误。
<更新>
按照建议,我将数据通过管道传输到一个文件:
psql <db_name> -c "COPY (SELECT row_number() OVER (), * FROM ds.my_data_set ds) TO stdout WITH (FORMAT csv, HEADER);" | head -n 1 > test.csv
我将其缩小到第一行 (CSV header)。将其通过管道传输到 cqlsh
使其因相同的错误而哭泣。然后,使用 python3.5 交互式 shell,我这样做了:
>>> with open('test.csv', 'rb') as fp:
... data = fp.read()
>>> data
b'row_number,..... Ist Einp\xc3\xb6ster ........`
我们就是这样,\xc3
真人。是 UTF-8 吗?
>>> data.decode('utf-8')
'row_number,....... Ist Einpöster ........`
是的,是 utf-8
。那么错误是如何发生的呢?
>>> data.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 336: ordinal not in range(128)
同样的错误文本,所以它可能也是 Python,但是没有堆栈跟踪,我不知道这是在哪里发生的,默认编码是 utf-8
。我尝试用 utf-8
覆盖默认值,但没有任何改变。不过,在某处,某些东西正在尝试使用 ASCII 解码流。
这是 server/client 上的 locale
:
LANG=
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8
Slack 上有人建议了这个答案UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)
一旦我在开头添加了 cqlsh.py
中的最后两行,它就解决了解码问题,但同一列被报告为无效并出现另一个错误:
:1:Invalid column name Ist Einpöster
旁注:
此时我对这个测试失去了兴趣,我只是想避免出现未回答的问题,请原谅等待时间。当我尝试将其作为分析引擎与 Spark 结合作为 Tableau 的数据源时,我发现了 "better" 个替代方案,例如 Vertica 和 ClickHouse。 "Better"因为两者都有局限性
更新>
如何完成导入?
我看不出您对此有任何答案。 UTF-8 应该 是默认值。
你试过了吗--encoding
?
文档:https://docs.scylladb.com/getting-started/cqlsh/
如果您在这里没有得到答案,您想在我们的 slack channel 上提问吗?
我会先尝试消除您那里的所有额外复杂性。尝试将几行转储到 CSV 中,然后使用 COPY
那是什么?
作为参数传入的查询包含列列表,其中包含具有非 ASCII 字符的列。在某些时候,cqlsh
将它们解析为 ascii 而不是 utf-8
,这导致了这个错误。
它是如何修复的?
第一次尝试是在 cqlsh
中添加这两行:
reload(sys)
sys.setdefaultencoding('utf-8')
但这仍然使脚本无法处理该列。
第二次尝试是简单地从文件传递查询。如果你不能,请知道 bash 支持进程替换,所以不要这样:
cqlsh -f path/to/query.cql
你可以
cqlsh -f <(echo "COPY .... FROM STDIN;")
一切都很好,只是它也不起作用。 cqlsh
从提示中将 stdin
理解为 "interactive",而不是通过管道输入。结果是它不导入任何内容。可以只创建一个文件,然后从文件中加载它,但这是一个额外的步骤,可能需要几分钟或几小时,具体取决于数据大小。
值得庆幸的是,POSIX 系统有像'/dev/stdin'这样的虚拟文件,所以上面的命令等同于:
cqlsh -f <(echo "COPY .... FROM '/dev/stdin';")
除了 cqlsh 现在认为您实际上有一个文件,并且它像文件一样读取它,因此您可以通过管道传输数据并感到高兴。
这可能会奏效,但出于某种原因我得到了最后一击:
cqlsh.sql:2:Failed to import 15 rows: InvalidRequest - Error from server: code=2200 [Invalid query] message="Batch too large", will retry later, attempt 4 of 5
我认为 15 行对于分布式存储引擎来说太多了,这很有趣。很可能它又是来自与 unicode 相关的引擎的一些限制,只是一条错误的错误消息。或者我错了。尽管如此,在 Slack 的一些人的大力帮助下,最初的问题得到了回答。
更新:utf8:打印无效的 UTF-8 字符位置
添加新的validate_with_error_position功能 which returns -1 如果数据是有效的 UTF-8 字符串 否则第一个无效的字节位置 特点。该职位被添加到例外 Scylla 中所有 UTF-8 解析错误的消息。
validate_with_error_position分两次完成 通过以保持相同的性能 通常情况下,当字符串有效时。
https://github.com/scylladb/scylla/commit/ffd8c8c505b92a71df7e34d5196c7545f11cb12f