heterodb / pg-strom

PG-Strom - Master development repository
http://heterodb.github.io/pg-strom/
Other
1.3k stars 162 forks source link

[VTJ-JP][arrow_fdw]Error occurs when IMPORT FOREIGN SCHEMA with "dir" option. #825

Closed sakaik closed 1 month ago

sakaik commented 1 month ago

概要

IMPORT FOREIGN SCHEMA で、オプションとして "dir" を指定した際にエラーになります。 実行例:

db=# IMPORT FOREIGN SCHEMA arrowtest
db-#   FROM SERVER arrow_fdw INTO public 
db-#  OPTIONS(dir '/opt/nvme/arrow_files/arrowdirtest/', suffix 'arrow');
ERROR:  'Field' of arrow type is not supported

詳細状況

Arrowファイル

このフォルダには3つのarrowファイルがあります。

-rw-r--r--. 1 sakaik sakaik 887M Oct  8 07:21 data1.arrow
-rw-r--r--. 1 sakaik sakaik 887M Oct  8 07:22 data2.arrow
-rw-r--r--. 1 sakaik sakaik 887M Oct  8 07:23 data3.arrow

各Arrowファイルは "file" オプションで読み込める

db=# IMPORT FOREIGN SCHEMA arrowtest1
db-#   FROM SERVER arrow_fdw INTO public 
db-#  OPTIONS(file '/opt/nvme/arrow_files/arrowdirtest/data1.arrow');
IMPORT FOREIGN SCHEMA

db=# IMPORT FOREIGN SCHEMA arrowtest2
db-#   FROM SERVER arrow_fdw INTO public 
db-#  OPTIONS(file '/opt/nvme/arrow_files/arrowdirtest/data2.arrow');
IMPORT FOREIGN SCHEMA

db=# IMPORT FOREIGN SCHEMA arrowtest3
db-#   FROM SERVER arrow_fdw INTO public 
db-#  OPTIONS(file '/opt/nvme/arrow_files/arrowdirtest/data3.arrow');
IMPORT FOREIGN SCHEMA

再現データ作成方法

データ作成用スクリプトの用意

https://github.com/heterodb/pg-strom/issues/824 に記載したpythonスクリプトを用意する。

データ生成~登録~Arrow化のためのシェルスクリプトファイルを用意

以下のシェルスクリプトファイルを用意する。DB名やDBユーザ名、出力先フォルダは適切に書き換える。

FILEID=$1
DB_NAME=sakaitest_nvme5
DB_USER=postgres
ARROW_OUTPATH=/opt/nvme/arrow_files/arrowdirtest
ARROW_BASENAME=data
TMP_TBL=arrowdir_tmp${FILEID}

echo ----- Processing ${FILEID} File. -----
echo "DROP TABLE IF EXISTS ${TMP_TBL};" | psql -U${DB_USER} -d ${DB_NAME}
echo "CREATE TABLE ${TMP_TBL} (id char(5), no integer, x varchar(20), y varchar(20), z varchar(20), a varchar(20), b varchar(20));" | psql -U${DB_USER} -d ${DB_NAME}
time python3 makeArrowTestData.py ${FILEID}| psql -U${DB_USER} -d ${DB_NAME} -c "\COPY ${TMP_TBL} FROM STDIN"
time pg2arrow -u ${DB_USER} -d ${DB_NAME} -t ${TMP_TBL} -n5 -o ${ARROW_OUTPATH}/${ARROW_BASENAME}${FILEID}.arrow
# echo "DROP TABLE ${TMP_TBL};" | psql -U${DB_USER} -d ${DB_NAME}

シェルスクリプトを実行

1,2,3のパラメタを与えて、シェルスクリプトを3回実行する(3つのArrowファイルが作成される)。

bash makeArrowTest.sh 1
bash makeArrowTest.sh 2
bash makeArrowTest.sh 3

Arrowファイルが作成されたら、上記 IMPORT FOREIGN SCHEMA の with Option で動作を確認できる。

sakaik commented 1 month ago

SELECT * で見るとそれっぽくデータが見えていたのですが、件数をが本来よりも多く認識されていることがわかりました。もとのpostgresテーブル(Arrow化する元のデータ)は1000万件です。

db=# SELECT COUNT(*) FROM arrowtest1;
  count   
----------
 11545600

id列は連番なので、この重複を確認することで状況がわかるだろうと見てみたところ・・・

db=# SELECT no,COUNT(*) FROM arrowtest1 GROUP BY no HAVING COUNT(*)>1;
 :
 7099069 |     4
 6081399 |     4
 4883584 |     4
 6350052 |     4
 6365021 |     4
 5623091 |     4
(2886400 rows)

4件ずつ存在するという結果が得られました(おかしい)。この際に、countが1件になるものは存在しません。

db=# SELECT no,COUNT(*) FROM arrowtest1 GROUP BY no HAVING COUNT(*)=1;
 no | count 
----+-------
(0 rows)

2886400 * 4 = 11545600 なので、ここの計算は整合しているようです。

また、このとき、以下のNOTICEが発生していました。

NOTICE:  arrow scan on 'arrowtest1' moved into 2th loop for inner-buffer partitions (pid: 200500)
NOTICE:  arrow scan on 'arrowtest1' moved into 4th loop for inner-buffer partitions (pid: 200500)
NOTICE:  arrow scan on 'arrowtest1' moved into 3th loop for inner-buffer partitions (pid: 202124)
sakaik commented 1 month ago

"dir"の問題として当初報告しましたが、そもそもひとつのArrowファイルが適切に生成されていない可能性(または正しく読み込めていない可能性)が高くなってきたので、その方面で追試を行いました。

COUNT()での件数が不正な値を返すようになるのは、今回の例のデータ(6 + int + 16 + 16 + 16 + 8 + 8 byteのレコード)だと、188.5万件~188.7万件の間に不正となる閾値があることが分かりました。(188.5万件以下のデータ件数(生成した件数)ではCOUNT()は正しい値を返す)。

また、16バイトではなく14バイトとしてデータ生成刺せた場合(6 + int + 14 + 14 + 14 + 8 + 8 byteのレコード)は、この閾値は 308.5万件と308.7万件の間へと変化します。

一定のデータサイズを超えた場合に pg2arrowが正常に動作しない可能性のように見えます。

sakaik commented 1 month ago

要らぬ情報かもしれませんが、追加情報を取得したので。 14バイト文字列にした3つの列を12バイトにした場合、つまり(6 + int + 12 + 12 + 12 + 8 + 8 byteのレコード)では、 331.3万でOK 331.5万で件数相違となりました。

sakaik commented 1 month ago

本issue、"dir"の問題 → "file"単体でもデータが変だった という点から 「pg2arrowの問題」として見ていましたが、どうも arrow_fdwの問題ではないかとの可能性が出てきたので、追加情報です。

(1) 単体でも正しく読めないarrowファイル data00410.arrow を、arrow2csvで変換、2列目(連番が入っている)だけを抽出

$ arrow2csv data00410.arrow | awk '(FS=","){print $2}' > z

(2) 出力された行数を確認 これは期待する件数と一致しています。

$ wc z
 33554432  33554431 290878777 z

(3) idがユニークとなる件数(種類数) 上の(2)と一致し、arrowファイル自体にはidの重複がないことがわかります(これを import foreign schemaするとidの重複があるように見えます)。

$ cat z | sort | uniq | wc
 33554432 33554431 290878777

故に、「pg2arrowは正常にarrowファイルを生成しているが、arrow_fdwが正しく読めていない」可能性として改めて報告いたします。

sakaik commented 1 month ago

複数のArrowファイルを比較する際に、FixedSizeBinary型への考慮が抜けていることが原因と思われます。 また、この時表示されるエラーメッセージ(default:の部分)は、a->node.tagName よりも a->type.node.tagName のほうがわかりやすいのではないでしょうか。

diff --git a/src/arrow_nodes.c b/src/arrow_nodes.c
index 5bee69e8..d2daf329 100644
--- a/src/arrow_nodes.c
+++ b/src/arrow_nodes.c
@@ -1033,6 +1033,7 @@ __arrowFieldTypeIsEqual(ArrowField *a, ArrowField *b, int depth)
                        }
                        break;
                case ArrowNodeTag__Utf8:
+               case ArrowNodeTag__FixedSizeBinary:
                case ArrowNodeTag__Binary:
                case ArrowNodeTag__Bool:
                        break;
@@ -1094,7 +1095,7 @@ __arrowFieldTypeIsEqual(ArrowField *a, ArrowField *b, int depth)

                default:
                        Elog("'%s' of arrow type is not supported",
-                                a->node.tagName);
+                                a->type.node.tagName);
        }
        return true;
 }
kaigai commented 1 month ago

FixedSizeBinaryの互換性チェックはbyteWidthの比較も必要ですので、 9d2df1d33422aa8076e01f81f91659badca86b61 でその辺も交えて修正してみました。 ご確認いただけますでしょうか?

sakaik commented 1 month ago

9d2df1 にて、当該Arrow filesが正常にIMPORTでき、テーブルとして参照できるようになったことを確認しました。 対応ありがとうございました。

db=# IMPORT FOREIGN SCHEMA mytable
db-#   FROM SERVER arrow_fdw INTO public 
db-#  OPTIONS(dir '/opt/nvme/mydata/arrow_files/', suffix 'arrow');
IMPORT FOREIGN SCHEMA
Time: 22589.879 ms (00:22.590)
db=# SELECT COUNT(*) FROM mytable;
    count    
-------------
 36943429632
(1 row)
db=# SELECT pgstrom.githash();
                 githash                  
------------------------------------------
 9d2df1d33422aa8076e01f81f91659badca86b61