Presto Verifier¶
Presto Verifier は、クエリを実行して正確性を検証するためのツールです。新しい Presto バージョンが正しいクエリ結果を生成するかどうかをテストしたり、Presto クエリペアが同じセマンティクスを持つかどうかをテストするために使用できます。
各 Presto リリース時に、Verifier を実行して、正確性の回帰がないことを確認します。
Verifier の使用¶
MySQL データベースで、次のテーブルを作成し、実行するクエリでロードします。
CREATE TABLE verifier_queries (
id int(11) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
suite varchar(256) NOT NULL,
name varchar(256) DEFAULT NULL,
control_catalog varchar(256) NOT NULL,
control_schema varchar(256) NOT NULL,
control_query text NOT NULL,
control_username varchar(256) DEFAULT NULL,
control_password varchar(256) DEFAULT NULL,
control_session_properties text DEFAULT NULL,
test_catalog varchar(256) NOT NULL,
test_schema varchar(256) NOT NULL,
test_query text NOT NULL,
test_username varchar(256) DEFAULT NULL,
test_password varchar(256) DEFAULT NULL,
test_session_properties text DEFAULT NULL)
次に、config.properties
ファイルを作成します。
source-query.suites=suite
source-query.database=jdbc:mysql://localhost:3306/mydb?user=my_username&password=my_password
control.hosts=127.0.0.1
control.http-port=8080
control.jdbc-port=8080
control.application-name=verifier-test
test.hosts=127.0.0.1
test.http-port=8081
test.jdbc-port=8081
test.application-name=verifier-test
test-id=1
Verifier は、設定 running-mode
を設定することで、query-bank
モードまたは control-test
モードのいずれかで実行できます。
control-test
: これはデフォルトモードです。制御クエリとテストクエリの両方が実行され、その結果のチェックサムが比較されます。query-bank
: このモードでは、制御クエリはスキップされ、保存されたスナップショット結果とテスト結果との間で比較が行われます。
verifier_snapshots
テーブルを作成します。
CREATE TABLE verifier_snapshots (
id int(11) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
suite varchar(256) NOT NULL,
name varchar(256) NOT NULL DEFAULT '.',
is_explain BOOLEAN NOT NULL DEFAULT false,
snapshot json NOT NULL,
updated_at datetime NOT NULL DEFAULT now(),
UNIQUE(suite, name, is_explain));
presto-verifier-0.289-executable.jar をダウンロードして、verifier.jar
に名前を変更します。Verifier を実行するには
java -Xmx1G -jar verifier.jar verify config.properties
query-bank
モードで実行する前に、スナップショットを保存する必要があります。設定を追加します。
running-mode=query-bank
save-snapshot=true
Verifier を実行すると、スナップショットが verifier_snapshots
テーブルに保存されます。
query-bank
モードで実行するには、save-snapshot=false
に設定するか、削除します。
running-mode=query-bank
#save-snapshot=true
Verifier プロシージャ¶
次の手順では、Verifier のワークフローをまとめます。
- ソースクエリのインポート
MySQL テーブルからソースクエリのリスト(設定を含むクエリペア)を読み取ります。
- クエリの事前処理とフィルタリング
各クエリのカタログ、スキーマ、ユーザー名、パスワードに上書きを適用します。
ホワイトリストとブラックリストに従ってクエリをフィルタリングします。ブラックリストの前にホワイトリストが適用されます。
無効な構文を持つクエリを除外します。
検証でサポートされていないクエリを除外します。
Select
、Insert
、CreateTableAsSelect
、create table
、create view
がサポートされています。
- クエリのリライト
本番データが変更されないように、実行前にクエリを書き換えます。
Select
クエリをCreateTableAsSelect
に書き換えます。列名は、
LIMIT 0
を使用してSelect
クエリを実行することで決定されます。名前のない列には人工的な名前が使用されます。
Insert
クエリとCreateTableAsSelect
クエリは、テーブル名が置き換えられるように書き換えます。Insert
クエリに必要なテーブルを作成するための設定クエリを構築します。
設定が設定されている場合、
nondeterministic-function-substitutes
に従って関数呼び出しを書き換えます。
- クエリの実行
概念的には、Verifier は制御クラスタとテストクラスタで構成されています。ただし、特定のテストでは、同じ Presto クラスタを指す場合があります。
Query-bank
モードでは、制御クラスタはスキップされ、代わりに保存されたスナップショットが使用されます。- 各ソースクエリについて、次のクエリを順番に実行します。
制御設定クエリ
制御クエリ
テスト設定クエリ
テストクエリ
制御とテストのティアダウンクエリ
- クエリはタイムアウトと再試行の対象となります。
クラスタ接続障害と一時的な Presto 障害は再試行されます。
クエリの再試行により、信頼性の問題が隠される可能性があるため、Verifier は再試行を含む発生したすべての Presto クエリ障害を記録します。
クエリの失敗の中には、クエリ中にパーティションが削除されたり、テーブルが削除されたりするなど、自動的に再検証のために送信されるものもあります。
障害解決 を参照して、クエリの失敗を自動的に解決してください。
- 結果の比較
Select
、Insert
、CreateTableAsSelect
クエリの場合、結果は一時テーブルに書き込まれます。制御とテストの両方に対してチェックサムクエリを構築して実行します。
query-bank
モードで実行している場合、制御チェックサムはmysql
データベースに保存されているスナップショットから復元されます。設定
save-snapshot
がtrue
に設定されている場合、制御チェックサムはmysql
データベースに保存されます。制御結果テーブルとテスト結果テーブルのテーブルスキーマと行数が同じであることを検証します。
各列のチェックサムが一致することを検証します。さまざまな列タイプの特別な処理については、列チェックサム を参照してください。
非決定論的クエリの処理については、決定性 を参照してください。
- 結果の出力
検証の結果は、
JSON
または人間が読めるテキストとしてエクスポートできます。
列チェックサム¶
制御/テストクエリの各列について、チェックサムクエリで 1 つ以上の列が生成されます。
- 浮動小数点列
DOUBLE
列とREAL
列の場合、検証のために 4 つの列が生成されます。列の有限値の合計
NAN
の列数正の無限大の列数
負の無限大の列数
NAN
の数、正の無限大の数、負の無限大の数が一致するかどうかを確認します。制御合計とテスト合計の NULL 値を確認します。
制御平均またはテスト平均のいずれかが 0 に非常に近い場合、両方が 0 に近いかどうかを確認します。
制御合計とテスト合計の相対誤差を確認します。
- VARCHAR 列
VARCHAR
列の場合、checksum()
を使用して、検証のために単純なチェックサム列が生成されます。validate-string-as-double
が設定されている場合、以下の 7 つの列が生成されます。すべての値をDOUBLE
にキャストする前と後で NULL の数が等しい場合、浮動小数点検証を適用します。そうでない場合は、単純なチェックサムが一致するかどうかを確認します。チェックサム
NULL 値の数
すべての値を
DOUBLE
にキャストした後の NULL 値の数
- すべての値を
DOUBLE
にキャストした後 有限値の合計
NAN
の値の数正の無限大の値の数
負の無限大の値の数
- 配列列
- 型
array(E)
の配列列arr
の場合、検証のために 3 つの列が生成されます。 カーディナリティの合計
カーディナリティのチェックサム
- 配列チェックサム
E
が順序付けできない場合、配列チェックサムはchecksum(arr)
です。E
が順序付け可能であれば、配列チェックサムはcoalesce(checksum(try(array_sort(arr))), checksum(arr))
となります。
- 型
use-error-margin-for-floating-point-arrays
が設定されており、E がDOUBLE
またはREAL
の場合、代わりに以下の6つの列が生成されます。基数の合計と基数のチェックサムが一致するかどうかを確認します。残りの結果には浮動小数点検証を適用します。カーディナリティの合計
カーディナリティのチェックサム
すべての配列値の有限要素の合計
すべての配列値の
NAN
要素の数すべての配列値の正の無限大要素の数
すべての配列値の負の無限大要素の数
validate-string-as-double
が設定されており、E がVARCHAR
の場合、代わりに以下の9つの列が生成されます。基数の合計とチェックサムが一致するかどうかを確認します。すべての配列要素をDOUBLE
にキャストする前後のNULL
の数が等しい場合、浮動小数点検証を適用します。そうでない場合、配列チェックサムが一致するかどうかを確認します。カーディナリティの合計
カーディナリティのチェックサム
配列チェックサム
checksum(array_sort(arr))
すべての配列値の
NULL
要素の数すべての配列要素を
DOUBLE
にキャストした後のNULL
要素の数
- すべての配列要素を
DOUBLE
にキャストした後 すべての配列値の有限要素の合計
すべての配列値の
NAN
要素の数すべての配列値の正の無限大要素の数
すべての配列値の負の無限大要素の数
- マップ列
map(K, V)
型のマップ列の場合、検証のために4つの列が生成されます。カーディナリティの合計
マップのチェックサム
キーセットの配列チェックサム
値セットの配列チェックサム
validate-string-as-double
が設定されており、K がVARCHAR
の場合、さらに6つの列が生成されます。すべてのキーセットの
NULL
要素の数すべてのマップキーを
DOUBLE
にキャストした後のキーセットのNULL
要素の数
- すべてのマップキーを
DOUBLE
にキャストした後 すべてのキーセットの有限要素の合計
すべてのキーセットの
NAN
要素の数すべてのキーセットの正の無限大要素の数
すべてのキーセットの負の無限大要素の数
validate-string-as-double
が設定されており、V がVARCHAR
の場合、さらに6つの列が生成されます。すべての値セットの
NULL
要素の数すべてのマップ値を
DOUBLE
にキャストした後の値セットのNULL
要素の数
- すべてのマップ値を
DOUBLE
にキャストした後 すべての値セットの有限要素の合計
すべての値セットの
NAN
要素の数すべての値セットの正の無限大要素の数
すべての値セットの負の無限大要素の数
- 行列
フィールドの種類に従って、行フィールドのチェックサムを再帰的に計算します。
その他のすべての列タイプでは、checksum()
関数を使用して単純なチェックサムを生成します。
決定性¶
行数の不一致や列の不一致など、結果の不一致は、非決定的なクエリ機能によって発生する可能性があります。誤検知を回避するために、制御クエリに対して決定性分析を実行します。クエリが非決定的なものであることが判明した場合、検証はスキップされます。なぜなら、それは洞察を提供しないからです。
決定性分析は以下の手順に従います。いずれかの時点でクエリが非決定的なものであることが判明した場合、分析は終了します。
非決定的なカタログは、
determinism.non-deterministic-catalog
で指定できます。クエリがこれらのカタログのいずれかのテーブルを参照している場合、そのクエリは非決定的なものと見なされます。制御クエリを再度実行し、結果を最初の制御クエリの実行結果と比較します。
- クエリに
LIMIT n
句があるが、最上位レベルにORDER BY
句がない場合 LIMIT
句のない制御クエリによって生成される行数をカウントするクエリを実行します。結果の行数が
n
より大きい場合、制御クエリを非決定的なものとして扱います。
- クエリに
障害解決¶
クラスタサイズを含む構成の違いにより、制御クラスタではクエリが成功するが、テストクラスタでは失敗する可能性があります。チェックサムクエリも失敗する可能性があり、これはPrestoまたはPresto Verifierの制限による可能性があります。そのため、Verifierが特定のクエリ障害を自動的に解決できるようにします。
EXCEEDED_GLOBAL_MEMORY_LIMIT
: 制御クエリがテストクエリよりも多くのメモリを使用している場合に解決します。EXCEEDED_TIME_LIMIT
: 無条件に解決します。TOO_MANY_HIVE_PARTITIONS
: テストクラスタに、各ワーカーに割り当てられるパーティション数が制限内にとどまるようにするための十分なワーカーがない場合に解決します。COMPILER_ERROR
、GENERATED_BYTECODE_TOO_LARGE
: 制御チェックサムクエリがこのエラーで失敗した場合に解決します。制御クエリに列が多すぎる場合、生成されたチェックサムクエリは特定のケースで大きくなりすぎる可能性があります。
結果の不一致の場合、Verifierはノイズの多いシグナルを出力している可能性があり、Verifierが特定の不一致を自動的に解決できるようにします。
- **構造化された列**: 配列要素またはマップのキー/値に浮動小数点型が含まれている場合、列のチェックサムは一致しない可能性が高いです。
配列列の場合、要素型に浮動小数点型が含まれており、基数のチェックサムが一致する場合に解決します。
- マップ列の場合、次の両方の条件が満たされているときに不一致を解決します。
基数のチェックサムが一致する。
浮動小数点型を含まないキーまたは値のチェックサムが一致する。
すべての列が解決された場合のみ、テストケースを解決します。
- **解決済み関数**: 結果の不一致の場合、クエリが指定されたリスト内の関数を使用している場合、テストケースは解決済みとしてマークされます。
指定リスト内の関数を使用している場合、テストケースは解決済みとしてマークされます。
説明モード¶
説明モードでは、Verifierは、同じ結果を生成するかどうかではなく、ソースクエリを説明できるかどうかを確認します。制御クエリとテストクエリの両方を説明できる場合、検証は成功としてマークされます。
出力イベントの matchType
フィールドは、制御実行とテスト実行の間に計画の違いがあるかどうかを示す指標として使用できます。
非DMLクエリの場合、制御クエリと計画の比較はスキップされます。
Verifierの拡張¶
Verifierは、構成プロパティに加えて、さらなる動作変更のために拡張できます。
AbstractVerifyCommand は、拡張できるコンポーネントを示しています。抽象クラスを実装し、PrestoVerifier と同様のコマンドラインラッパーを作成します。
構成リファレンス¶
一般構成¶
名前 |
説明 |
---|---|
|
検証するクエリの名前をコンマ区切りで指定します。 |
|
スイートから除外するクエリの名前をコンマ区切りで指定します。 |
|
ソースクエリサプライヤーの名前。 |
|
Verifierクエリを保持するテーブルの名前。 |
|
出力イベントを出力する場所をコンマ区切りで指定します。 |
|
|
|
人間が判読可能なイベントの出力ファイル。設定されていない場合、人間が判読可能なイベントは |
|
制御ターゲットテーブルに追加するテーブルプレフィックス。 |
|
テストターゲットテーブルに追加するテーブルプレフィックス。 |
|
|
|
|
|
出力イベントに添付する文字列。 |
|
同時検証の最大数。 |
|
スイートが検証される回数。 |
|
ソースクエリが検証される回数。 |
|
浮動小数点列の制御合計とテスト合計の間で許容できる最大相対誤差。 |
|
この閾値を下回る浮動小数点平均は |
|
結果が一致しない場合にクリーンアップクエリを実行するかどうか。 |
|
検証のためにソースクエリを再送信できる回数の制限。 |
|
Verifierを |
|
|
|
|
|
カンマで関数置換を連結します。 有効なソースクエリを生成するために、元の関数の戻り値の型と引数の型と互換性のある関数置換を選択します。例: 関数置換に適用する必要がある場合は、関数引数を識別子として宣言します。 |
クエリ上書き設定¶
次の設定は、検証開始前にクエリメタデータの変更の動作を制御します。接頭辞control
をtest
に置き換えたテストクエリについても、同様の設定が可能です。
名前 |
説明 |
---|---|
|
指定された場合、すべてのクエリに適用されるカタログ。 |
|
指定された場合、すべてのクエリに適用されるスキーマ。 |
|
指定された場合、すべてのクエリに適用されるユーザー名。 |
|
指定された場合、すべてのクエリに適用されるパスワード。 |
|
3つの値をサポートします。 |
|
すべてのクエリに適用されるセッションプロパティ。 |
クエリ実行設定¶
次の設定は、コントロールクラスタでのクエリ実行の動作を制御します。接頭辞control
をtest
に置き換えたテストクラスタについても、同様の設定が可能です。
名前 |
説明 |
---|---|
|
コントロールクラスタのホスト名またはIPアドレスのカンマ区切りリスト。 |
|
コントロールクラスタのJDBCポート。 |
|
コントロールクラスタのHTTPポート。 |
|
コントロールJDBCの追加のURLパラメータを表す |
|
コントロールクエリとテストクエリのタイムアウト。 |
|
|
|
チェックサムクエリのタイムアウト。 |
|
ClientInfoに渡されるApplicationName。ソースを設定するために使用できます。 |
決定性アナライザ設定¶
名前 |
説明 |
---|---|
|
決定性分析で生成されたテーブルに対してクリーンアップクエリを実行するかどうか。 |
|
コントロールクエリの決定性を確認するための追加のコントロール実行の最大回数。 |
|
最上位レベルに |
|
非決定論的カタログのカンマ区切りリスト。これらのカタログからのテーブルを参照するクエリは、非決定論的として扱われます。 |
障害解決設定¶
名前 |
説明 |
---|---|
|
|
|
|
|
Verifierの制限による失敗に対する障害解決を有効にするかどうか。 |
|
|
|
コントロールクラスタとテストクラスタで設定されている、ライターあたりの最大バケット数。 |
|
テストクラスタのサイズがキャッシュされるタイムアウト。 |
|
構造化型列の列の不一致に対する障害解決を有効にするかどうか。 |
|
|
|
カンマ区切りの関数リスト。クエリがこのリスト内の関数を使用している場合、不一致を解決します。 |