Dictionaryは、JOIN操作を高速化するためにDorisが提供する特別なデータ構造です。通常のテーブルをベースとして構築され、元のテーブルの対応する列をkey-valueの関係として扱い、これらの列のすべてのデータを事前にメモリにロードして高速な検索操作を実現し、クエリのパフォーマンスを向上させます。頻繁なkey-value検索が必要なシナリオに特に適しています。
当然ながら、key-value検索ソリューションとして、dictionaryテーブルは重複するキーを許可しません。
dictionaryテーブルは主に以下のシナリオに適しています:
元々LEFT OUTER JOINを使用して実装する必要があったkey-value検索は、dictionaryテーブルの助けを借りて完全に排除でき、通常の関数呼び出しに変換されます。以下は完全なシナリオ例です:
Eコマースシステムにおいて、注文テーブル(orders、ファクトテーブル)は大量の取引データを記録し、製品テーブル(products、ディメンションテーブル)と頻繁に関連付けて、詳細な製品情報を取得する必要があります。
-- Product Dimension Table CREATE TABLE products ( product_id BIGINT NOT NULL COMMENT "商品ID", product_name VARCHAR(128) NOT NULL COMMENT "商品名称", brand_name VARCHAR(64) NOT NULL COMMENT "品牌名称", category_name VARCHAR(64) NOT NULL COMMENT "品类名称", retail_price DECIMAL(10,2) NOT NULL COMMENT "零售价", update_time DATETIME NOT NULL COMMENT "更新时间" ) DISTRIBUTED BY HASH(`product_id`) BUCKETS 10; -- Order Fact Table CREATE TABLE orders ( order_id BIGINT NOT NULL COMMENT "订单ID", product_id BIGINT NOT NULL COMMENT "商品ID", user_id BIGINT NOT NULL COMMENT "用户ID", quantity INT NOT NULL COMMENT "购买数量", actual_price DECIMAL(10,2) NOT NULL COMMENT "实际成交价", order_time DATETIME NOT NULL COMMENT "下单时间" ) DISTRIBUTED BY HASH(`order_id`) BUCKETS 32; INSERT INTO products VALUES (1001, 'iPhone 15 Pro 256G 黑色', 'Apple', '手机数码', 8999.00, '2024-01-01 00:00:00'), (1002, 'MacBook Pro M3 Max', 'Apple', '电脑办公', 19999.00, '2024-01-01 00:00:00'), (1003, 'AirPods Pro 2', 'Apple', '手机配件', 1999.00, '2024-01-01 00:00:00'); INSERT INTO orders VALUES (10001, 1001, 88001, 1, 8899.00, '2024-02-22 10:15:00'), (10002, 1002, 88002, 1, 19599.00, '2024-02-22 11:30:00'), (10003, 1003, 88001, 2, 1899.00, '2024-02-22 14:20:00');
以下は典型的なクエリのセットです。各カテゴリの注文数量と売上を集計するために、過去には、商品テーブルから商品情報を抽出する機能を実現するためにLEFT OUTER JOINを使用する必要がありました。
-- Analyze the order volume and sales revenue of each category SELECT p.category_name, p.brand_name, COUNT(DISTINCT o.order_id) as order_count, SUM(o.quantity) as total_quantity, SUM(o.actual_price * o.quantity) as total_amount FROM orders o LEFT JOIN products p ON o.product_id = p.product_id WHERE o.order_time >= '2024-02-22 00:00:00' GROUP BY p.category_name, p.brand_name ORDER BY total_amount DESC;
+---------------+------------+-------------+----------------+--------------+ | category_name | brand_name | order_count | total_quantity | total_amount | +---------------+------------+-------------+----------------+--------------+ | 电脑办公 | Apple | 1 | 1 | 19599.00 | | 手机数码 | Apple | 1 | 1 | 8899.00 | | 手机配件 | Apple | 1 | 2 | 3798.00 | +---------------+------------+-------------+----------------+--------------+
このようなクエリでは、product_idを使用して製品に関する他の情報を頻繁に取得する必要があり、これは本質的にKVルックアップ操作を伴います。
キーバリューペアの関係を設定し、対応する辞書テーブルを事前構築することで、以前のJOIN操作を完全により軽量なキーバリュールックアップに変換でき、それによりSQL実行効率を向上させることができます:
-- Create product information dictionary CREATE DICTIONARY product_info_dict USING products ( product_id KEY, product_name VALUE, brand_name VALUE, category_name VALUE, retail_price VALUE ) LAYOUT(HASH_MAP) PROPERTIES( 'data_lifetime'='300' -- Considering the frequency of changes in product information, set the update interval to 5 minutes. );
元のクエリは、JOIN操作を辞書テーブルを使用したdict_get関数ルックアップに変換します。これはより軽量なKVルックアップ操作です。
SELECT dict_get("test.product_info_dict", "category_name", o.product_id) as category_name, dict_get("test.product_info_dict", "brand_name", o.product_id) as brand_name, COUNT(DISTINCT o.order_id) as order_count, SUM(o.quantity) as total_quantity, SUM(o.actual_price * o.quantity) as total_amount FROM orders o WHERE o.order_time >= '2024-02-22 00:00:00' GROUP BY dict_get("test.product_info_dict", "category_name", o.product_id), dict_get("test.product_info_dict", "brand_name", o.product_id) ORDER BY total_amount DESC;
+---------------+------------+-------------+----------------+--------------+ | category_name | brand_name | order_count | total_quantity | total_amount | +---------------+------------+-------------+----------------+--------------+ | 电脑办公 | Apple | 1 | 1 | 19599.00 | | 手机数码 | Apple | 1 | 1 | 8899.00 | | 手机配件 | Apple | 1 | 2 | 3798.00 | +---------------+------------+-------------+----------------+--------------+
CREATE DICTIONARY <dict_name> USING <source_table> ( <key_column> KEY[, ..., <key_columns> VALUE] <value_column> VALUE[, ..., <value_columns> VALUE] ) LAYOUT(<layout_type>) PROPERTIES( "<priority_item_key>" = "<priority_item_value>"[, ..., "<priority_item_key>" = "<priority_item_value>"] );
以下の要素から:
<dict_name>: 辞書テーブルの名前<source_table>: ソースデータテーブル<key_column>: キーとして機能するソーステーブル内の列名<value_column>: 値として機能するソーステーブル内の列名<layout_type>: 辞書テーブルのストレージレイアウトタイプ、詳細は後述<priority_item_key>: テーブルの特定のプロパティの名前<priority_item_value>: テーブルの特定のプロパティの値<key_column>と<value_column>はそれぞれ少なくとも1つが必要です。<key_column>は<value_column>の前に現れる必要はありません。
現在、2つのレイアウトタイプがサポートされています:
HASH_MAP: ハッシュテーブルベースの実装で、一般的なキー・バリュー検索シナリオに適しています。
IP_TRIE: Trieツリーベースの実装で、IPアドレスタイプの検索に特化して最適化されています。Key列はIPアドレスをCIDR記法で表現する必要があり、クエリはCIDR記法に従ってマッチングされます。
| プロパティ名 | 値タイプ | 意味 | 必須 |
|---|---|---|---|
date_lifetime | 整数、単位は秒 | データの有効期間。この辞書の最後の更新からの経過時間がこの値を超え、ソーステーブルにデータ変更がある場合、自動的にインポートを開始します。インポートロジックの詳細はAutomatic Importを参照してください | はい |
skip_null_key | Boolean | 辞書にロードする際にKey列にnull値が含まれている場合、値がtrueの場合はその行をスキップし、そうでなければエラーを発生させます。デフォルト値はfalseです | いいえ |
memory_limit | 整数、単位はバイト | 単一BE上でこの辞書が占有するメモリの上限。デフォルト値は2147483648で、2GBに相当します。 | いいえ |
-- Create source data table CREATE TABLE source_table ( id INT NOT NULL, city VARCHAR(32) NOT NULL, code VARCHAR(32) NOT NULL ) ENGINE=OLAP DISTRIBUTED BY HASH(id) BUCKETS 1; -- Create dictionary table CREATE DICTIONARY city_dict USING source_table ( city KEY, id VALUE ) LAYOUT(HASH_MAP) PROPERTIES('data_lifetime' = '600');
テーブルに基づいて、source_tableのcityの値に基づいて対応するidをクエリするために、dict_get関数を通じて辞書city_dictを使用できます。
Keyカラム
Null値の処理
skip_null_keyに依存します。辞書は自動および手動インポートをサポートします。「インポート」はここでは「リフレッシュ」とも呼ばれます。
自動インポートは以下の時点で発生します:
Dorisはdictionary_auto_refresh_interval_seconds秒ごとにすべての辞書データの期限切れをチェックします。辞書がdata_lifetime秒以上更新されておらず、ソーステーブルデータが最後のインポートと比較して変更されている場合、Dorisはその辞書のインポートを自動的に送信します。
一部のBEでデータが不足しており、ソーステーブルデータが最後のインポートと比較して変更されていない場合、Dorisは対応するBEの現在のバージョンのデータのみを補完し、すべてのBEに対してリフレッシュタスクを送信せず、辞書のバージョンは変更されません。
Dorisは以下のコマンドを通じて辞書データの手動リフレッシュをサポートします:
REFRESH DICTIONARY <dict_name>;
それらの中で、<dict_name>はインポートする辞書の名前です。
LOADING)、手動インポートは失敗します。進行中のインポートが完了するまで待ってから実行してください。memory_limitを超える場合、インポートトランザクションは失敗します。単一Key、Valueリストおよび複数Key、Valueリストの辞書テーブルクエリには、それぞれdict_getおよびdict_get_many関数を使用できます。
辞書への最初のクエリを実行する前に、辞書がインポートされるまで待ってください。
dict_get("<db_name>.<dict_name>", "<query_column>", <query_key_value>); dict_get_many("<db_name>.<dict_name>", <query_columns>, <query_key_values>);
この中で:
<db_name> は辞書が配置されているデータベースの名前です。<dict_name> は辞書の名前です<query_column> はクエリする値列の列名で、型は VARCHAR です。定数でなければなりません<query_columns> はクエリするすべての値列の列名で、型は ARRAY<VARCHAR> です。定数でなければなりません。<query_key_value> はクエリで使用されるキー列のデータです<query_key_values> は辞書でクエリするデータのすべてのキー列を含む STRUCT です。dict_get の戻り値の型は <query_column> に対応する辞書列の型です。 dict_get_many の戻り値の型は <query_columns> 内の各辞書列の型に対応する STRUCT です。
このステートメントは test_db データベース内の辞書 city_dict に対して、key 列の値が「Beijing」の場合の対応する id 値をクエリします:
SELECT dict_get("test_db.city_dict", "id", "Beijing");
この文は、test_dbデータベース内の辞書single_key_dictに対して、key列の値が1の場合におけるk1とk3の対応する値をクエリします:
SELECT dict_get_many("test_db.single_key_dict", ["k1", "k3"], struct(1));
このステートメントは、test_dbデータベース内の辞書multi_key_dictに対してクエリを実行し、2つのキー列の値が順番に2と‘ABC’である場合の対応するk2とk3列の値を取得します:
SELECT dict_get_many("test_db.multi_key_dict", ["k2", "k3"], struct(2, 'ABC'));
例えば、テーブル作成文は以下の通りです:
create table if not exists multi_key_table( k0 int not null, k1 varchar not null, k2 float not null, k3 varchar not null ) DISTRIBUTED BY HASH(`k0`) BUCKETS auto; create dictionary multi_key_dict using multi_key_table ( k0 KEY, k1 KEY, k2 VALUE, k3 VALUE ) LAYOUT(HASH_MAP) PROPERTIES('data_lifetime' = '600');
その後、上記のステートメント
SELECT dict_get_many("test_db.multi_key_dict", ["k2", "k3"], struct(2, 'ABC'));
STRUCT<float, varchar>型を返します。
<query_key_value>の型はIPV4またはIPV6でなければなりません。<key_column>のデータとクエリに使用される<query_key_value>の両方がIPV4およびIPV6形式のデータをサポートします。dictionary_auto_refresh_interval_secondsの値を減らすことで、辞書が利用できない時間を短縮できます。辞書テーブルは以下の管理および表示ステートメントをサポートします:
現在のデータベース内のすべての辞書テーブルのステータスを確認します。
SHOW DICTIONARIES [LIKE <LIKE_NAME>];
特定の辞書の定義を確認する
DESC DICTIONARY <dict_name>;
辞書テーブルを削除する
DROP DICTIONARY <dict_name>;
辞書テーブルを削除した後、削除された辞書がBEから即座に削除されない場合があります。
辞書テーブルは以下の設定項目をサポートしており、すべてFE CONFIGです:
dictionary_task_queue_size —— 辞書内のすべてのタスクに対するスレッドプールのキューの長さは動的に調整できません。デフォルト値は1024で、通常調整する必要はありません。job_dictionary_task_consumer_thread_num —— 辞書内のすべてのタスクに対するスレッドプール内のスレッド数は動的に調整できません。デフォルト値は3です。dictionary_rpc_timeout_ms —— 辞書内のすべての関連RPCのタイムアウト時間は動的に調整できます。デフォルトは5000(つまり5秒)で、通常調整する必要はありません。dictionary_auto_refresh_interval_seconds —— すべての辞書データが最新であるかを自動的にチェックする間隔はデフォルト5(秒)で、動的に調整できます。SHOW DICTIONARIES文を使用することで、辞書に対応するベーステーブル、現在のデータバージョン番号、およびFEとBEでの対応するステータスを確認できます:
> SHOW DICTIONARIES;
+--------------+----------------+----------------------------------------------+---------+--------+------------------------------------+------------------------------+ | DictionaryId | DictionaryName | BaseTableName | Version | Status | DataDistribution | LastUpdateResult | +--------------+----------------+----------------------------------------------+---------+--------+------------------------------------+------------------------------+ | 51 | precision_dict | internal.test_refresh_dict.precision_test | 2 | NORMAL | {10.16.10.2:9767 ver=2 memory=368} | 2025-02-18 09:58:12: succeed | | 48 | product_dict | internal.test_refresh_dict.product_info | 2 | NORMAL | {10.16.10.2:9767 ver=2 memory=240} | 2025-02-18 09:58:12: succeed | | 49 | ip_dict | internal.test_refresh_dict.ip_info | 2 | NORMAL | {10.16.10.2:9767 ver=2 memory=194} | 2025-02-18 09:58:12: succeed | | 52 | order_dict | internal.test_refresh_dict.column_order_test | 2 | NORMAL | {10.16.10.2:9767 ver=2 memory=432} | 2025-02-18 09:58:12: succeed | | 50 | user_dict | internal.test_refresh_dict.user_info | 2 | NORMAL | {10.16.10.2:9767 ver=2 memory=240} | 2025-02-18 09:58:12: succeed | +--------------+----------------+----------------------------------------------+---------+--------+------------------------------------+------------------------------+
内容:
Versionはデータのバージョン番号を表し、データがインポートされるたびに1ずつ増加します。
Statusは辞書のステータスを表し、意味は以下の通りです:
| Status Name | 意味 |
|---|---|
| NORMAL | 辞書は現在正常です |
| LOADING | 辞書は現在インポート中です |
| OUT_OF_DATE | 現在の辞書データは期限切れです |
辞書がインポート中の間は、再度インポートすることはできません。
DataDistributionは各BEの現在のステータスを表し、バージョン番号とメモリ使用サイズ(KB)が含まれます。
LastUpdateResultは最後のインポート(自動および手動を含む)の結果を示し、例外がある場合は詳細なエラーメッセージがここに表示されます。
辞書テーブルのカラム定義を確認するには、DESC DICTIONARYを使用できます。例:
> DESC DICTIONARY city_code_dict; +-------------+-------------+------+-------+ | Field | Type | Null | Key | +-------------+-------------+------+-------+ | city_name | varchar(32) | NO | true | | region_code | varchar(32) | NO | false | +-------------+-------------+------+-------+
データの整合性
data_lifetimeを適切に設定して自動更新を実現し、ビジネスロジックに基づいて必要に応じて手動で更新する必要があります。パフォーマンスに関する考慮事項
辞書テーブルは、ディメンションテーブルデータなど、比較的静的なデータに適しています。
辞書テーブルは純粋なインメモリテーブルで、全データがすべてのBEのメモリに格納され、大量のメモリを占有する可能性があるため、メモリ使用量とクエリパフォーマンスを比較検討して辞書を導出する適切なテーブルを選択する必要があります。
ベストプラクティス
キー値カラムの合理的な選択:
レイアウトの選択:
状態管理:
HASH_MAP
-- Create source data table CREATE TABLE cities ( city_id INT NOT NULL, city_name VARCHAR(32) NOT NULL, region_code VARCHAR(32) NOT NULL ) ENGINE=OLAP DISTRIBUTED BY HASH(city_id) BUCKETS 1; INSERT INTO cities VALUES (1, 'Beijing', 'BJ'), (2, 'Shanghai', 'SH'), (3, 'Guangzhou', 'GZ'); -- Create dictionary table CREATE DICTIONARY city_code_dict USING cities ( city_name KEY, region_code VALUE ) LAYOUT(HASH_MAP) PROPERTIES('data_lifetime' = '600'); -- Query using a dictionary table SELECT dict_get("test_refresh_dict.city_code_dict", "region_code", "Beijing");
+------------------------------------------------------------------------+ | dict_get('test_refresh_dict.city_code_dict', 'region_code', 'Beijing') | +------------------------------------------------------------------------+ | BJ | +------------------------------------------------------------------------+
IP_TRIE
CREATE TABLE ip_locations ( ip_range VARCHAR(30) NOT NULL, country VARCHAR(64) NOT NULL, region VARCHAR(64) NOT NULL, city VARCHAR(64) NOT NULL ) ENGINE=OLAP DISTRIBUTED BY HASH(ip_range) BUCKETS 1; INSERT INTO ip_locations VALUES ('1.0.0.0/24', 'United States', 'California', 'Los Angeles'), ('1.0.1.0/24', 'China', 'Beijing', 'Beijing'), ('1.0.4.0/24', 'Japan', 'Tokyo', 'Tokyo'); -- Create an IP address dictionary table CREATE DICTIONARY ip_location_dict USING ip_locations ( ip_range KEY, country VALUE, region VALUE, city VALUE ) LAYOUT(IP_TRIE) PROPERTIES('data_lifetime' = '600'); -- Query the location information corresponding to the IP address, based on CIDR matching. SELECT dict_get("test_refresh_dict.ip_location_dict", "country", cast('1.0.0.1' as ipv4)) AS country, dict_get("test_refresh_dict.ip_location_dict", "region", cast('1.0.0.2' as ipv4)) AS region, dict_get("test_refresh_dict.ip_location_dict", "city", cast('1.0.0.3' as ipv4)) AS city;
+---------------+------------+-------------+ | country | region | city | +---------------+------------+-------------+ | United States | California | Los Angeles | +---------------+------------+-------------+
マルチキー/マルチバリューを持つHASH_MAP
-- Product SKU Dimension Table: Includes basic product attributes CREATE TABLE product_sku_info ( product_id INT NOT NULL COMMENT "商品ID", color_code VARCHAR(32) NOT NULL COMMENT "颜色编码", size_code VARCHAR(32) NOT NULL COMMENT "尺码编码", product_name VARCHAR(128) NOT NULL COMMENT "商品名称", color_name VARCHAR(32) NOT NULL COMMENT "颜色名称", size_name VARCHAR(32) NOT NULL COMMENT "尺码名称", stock INT NOT NULL COMMENT "库存", price DECIMAL(10,2) NOT NULL COMMENT "价格", update_time DATETIME NOT NULL COMMENT "更新时间" ) DISTRIBUTED BY HASH(`product_id`) BUCKETS 10; -- Order Details Table: Records actual sales data CREATE TABLE order_details ( order_id BIGINT NOT NULL COMMENT "订单ID", product_id INT NOT NULL COMMENT "商品ID", color_code VARCHAR(32) NOT NULL COMMENT "颜色编码", size_code VARCHAR(32) NOT NULL COMMENT "尺码编码", quantity INT NOT NULL COMMENT "购买数量", order_time DATETIME NOT NULL COMMENT "下单时间" ) DISTRIBUTED BY HASH(`order_id`) BUCKETS 10; -- Insert product SKU data INSERT INTO product_sku_info VALUES (1001, 'BLK', 'M', 'Nike运动T恤', '黑色', 'M码', 100, 199.00, '2024-02-23 10:00:00'), (1001, 'BLK', 'L', 'Nike运动T恤', '黑色', 'L码', 80, 199.00, '2024-02-23 10:00:00'), (1001, 'WHT', 'M', 'Nike运动T恤', '白色', 'M码', 90, 199.00, '2024-02-23 10:00:00'), (1001, 'WHT', 'L', 'Nike运动T恤', '白色', 'L码', 70, 199.00, '2024-02-23 10:00:00'), (1002, 'RED', 'S', 'Adidas运动裤', '红色', 'S码', 50, 299.00, '2024-02-23 10:00:00'), (1002, 'RED', 'M', 'Adidas运动裤', '红色', 'M码', 60, 299.00, '2024-02-23 10:00:00'), (1002, 'BLU', 'S', 'Adidas运动裤', '蓝色', 'S码', 55, 299.00, '2024-02-23 10:00:00'), (1002, 'BLU', 'M', 'Adidas运动裤', '蓝色', 'M码', 65, 299.00, '2024-02-23 10:00:00'); -- Insert order data INSERT INTO order_details VALUES (10001, 1001, 'BLK', 'M', 2, '2024-02-23 12:01:00'), (10002, 1001, 'WHT', 'L', 1, '2024-02-23 12:05:00'), (10003, 1002, 'RED', 'S', 1, '2024-02-23 12:10:00'), (10004, 1001, 'BLK', 'L', 3, '2024-02-23 12:15:00'), (10005, 1002, 'BLU', 'M', 2, '2024-02-23 12:20:00'); -- Create a multi-key multi-value dictionary CREATE DICTIONARY sku_dict USING product_sku_info ( product_id KEY, color_code KEY, size_code KEY, product_name VALUE, color_name VALUE, size_name VALUE, price VALUE, stock VALUE ) LAYOUT(HASH_MAP) PROPERTIES('data_lifetime'='300'); -- Query example using dict_get_many: Retrieve order details and SKU information WITH order_sku_info AS ( SELECT o.order_id, o.quantity, o.order_time, dict_get_many("test.sku_dict", ["product_name", "color_name", "size_name", "price", "stock"], struct(o.product_id, o.color_code, o.size_code) ) as sku_info FROM order_details o WHERE o.order_time >= '2024-02-23 12:00:00' AND o.order_time < '2024-02-23 13:00:00' ) SELECT order_id, order_time, struct_element(sku_info, 'product_name') as product_name, struct_element(sku_info, 'color_name') as color_name, struct_element(sku_info, 'size_name') as size_name, quantity, struct_element(sku_info, 'price') as unit_price, quantity * struct_element(sku_info, 'price') as total_amount, struct_element(sku_info, 'stock') as current_stock FROM order_sku_info ORDER BY order_time;
+----------+---------------------+-----------------+------------+-----------+----------+------------+--------------+---------------+ | order_id | order_time | product_name | color_name | size_name | quantity | unit_price | total_amount | current_stock | +----------+---------------------+-----------------+------------+-----------+----------+------------+--------------+---------------+ | 10001 | 2024-02-23 12:01:00 | Nike运动T恤 | 黑色 | M码 | 2 | 199.00 | 398.00 | 100 | | 10002 | 2024-02-23 12:05:00 | Nike运动T恤 | 白色 | L码 | 1 | 199.00 | 199.00 | 70 | | 10003 | 2024-02-23 12:10:00 | Adidas运动裤 | 红色 | S码 | 1 | 299.00 | 299.00 | 50 | | 10004 | 2024-02-23 12:15:00 | Nike运动T恤 | 黑色 | L码 | 3 | 199.00 | 597.00 | 80 | | 10005 | 2024-02-23 12:20:00 | Adidas运动裤 | 蓝色 | M码 | 2 | 299.00 | 598.00 | 65 | +----------+---------------------+-----------------+------------+-----------+----------+------------+--------------+---------------+
クエリで「can not find dict name」エラーが報告される
最初に、SHOW DICTIONARIESを使用して辞書の存在を確認してください。存在する場合は、対応する辞書データを更新してください。
クエリで「dict_get() only support IP type for IP_TRIE」エラーが報告される
IP_TRIE型辞書のKeyカラムがCIDR形式に厳密に準拠しているかどうかを確認してください。
インポート時に「Version ID is not greater than the existing version ID for the dictionary.」エラーが報告される
DROP DICTIONARYコマンドを使用して対応する辞書を削除し、再作成してからデータをインポートしてください。
SHOW DICTIONARIESの結果で、辞書がFEバージョンより大きいBEバージョンにあることが表示される
DROP DICTIONARYコマンドを使用して対応する辞書を削除し、再作成してからデータをインポートしてください。
インポート時に「Dictionary X commit version Y failed」エラーが報告される
辞書を再更新してください。
緊急時対応戦略
大多数のエラーメッセージについて、通常の操作が失敗する場合、DROP後に辞書を再構築することで問題を解決できます。