GridDBのパーティショニングと期限切れ

期限切れリリースを含むルールは、データベースをスリムで軽快に保つのに役立ちます。この記事では、GridDBのパーティショニング機能と密接に結びついたGridDBの期限切れ機能を紹介します。この記事を読み進めると、パーティショニングと期限切れルールを持つコンテナの作成方法と、テーブルを作成し、テーブルにプッシュされたデータのどの行が保存され、どの行が(期限切れのため)即座にダンプされるかを調べる小さなpythonスクリプトを学ぶことができます。

特別なお知らせ

このコースでは、GridDBを永続ストレージとして利用するフルスタックのJavaアプリケーションを構築します。このコースは100%無料で、どなたでも受講できます: https://www.udemy.com/course/building-a-full-stack-java-application-part-ii

このコースでは、GridLogと呼ばれるアプリを作成し、検索可能なフィールドとログビューアを備えた永続ストレージにコンピュータのログを保存できるようにします。今すぐ登録して、GridDBとそれを使ったアプリ構築についてさらに学びましょう。

前提条件

GridDB、Java、Python、そしてGridDB Python Clientのインストールが必要です。

GridDBのコンテナやテーブルをパーティショニングルール付きで作成するにはSQLを使用する必要があります。この記事では、 jpype という python ライブラリを通して JDBC 経由で GridDB に接続する非常にシンプルな python スクリプトを使用します。このプロジェクトで使用する全ての python ライブラリの requirements.txt ファイルを用意しました。

このプロジェクトのすべてのソースコードは https://github.com/griddbnet/Blogs/tree/partitioning_expiry にあります。

リポジトリは以下のようにcloneできます:

$ git clone https://github.com/griddbnet/Blogs.git --branch partitioning_expiry

GridDBとパーティショニング

有効期限解放機能についての記事で、なぜパーティショニングにフォーカスが当たっているのか不思議に思うかもしれないが、それは有効期限解放がパーティショニングに依存しているからです。つまり、期限切れルールを設定するためには、テーブルも何らかのパーティショニング・ルールを宣言する必要があります。

GridDBには3種類のパーティショニングがあります: インターバル・パーティショニング、ハッシュ・パーティショニング、インターバル・ハッシュ・パーティショニングだ。インターバル・パーティショニング、ハッシュ・パーティショニング、インターバル・ハッシュ・パーティショニングです。インターバル・パーティショニングは、時間ベースのパーティショニングです。ハッシュ・パーティショニングでは有効期限を設定することはできません。つまり、私たちは主にインターバル・パーティショニングとインターバル・ハッシュ・パーティショニングに焦点を当てます。

パーティション分割されたテーブルを作成する具体的な方法を紹介する前に、これらの異なるパーティショニング方法が何を意味するのかを簡単に復習しておきましょう。

ハッシュ・パーティショニング

このタイプのパーティショニングは、時系列コンテナとコレクション・コンテナの両方で使用できます。このタイプのパーティショニングされたテーブルの行は、テーブル全体で均等に分散されます。このパーティショニングを使用する利点は、任意の型を取ることができ、時間ベースの列データ型に依存しないことです。

インターバル・パーティショニング

前述したように、これらのテーブルは時間ベースのインターバルでパーティショニングされます: 「テーブルの行は指定されたインターバル値で分割され、データパーティションに格納されます。各パーティションの上限と下限は、ルールに基づいてGridDBが自動的に設定します。

このパーティショニングはTIME_SERIESコンテナとそのrowkey(これらは常にTIMESTAMP型である)で機能するが、いくつかのルールを追加することでコレクションコンテナでも機能します。コレクションコンテナを使用する場合は、パーティショニングカラムを TIMESTAMP 型に設定する必要があり、 その時間ベースのカラムを NOT NULL かつ PRIMARY KEY として設定する必要があります。

インターバル・ハッシュ・パーティショニング

お察しの通り、このパーティショニング方法は上記の2つの方法を組み合わせたものです。まずインターバルに基づいてパーティショニングを行い、さらにハッシュに基づいてパーティショニングを行います。区間分割カウントとハッシュ分割カウントを掛け合わせることで、パーティショニングの全量を計算することができます。

それぞれの分割方法をいつ使うか

どのような場合にどのパーティショニング方法を使うべきかという質問があると思いますが、それはとても簡単です。もしデータが時間的に均等に分割できるのであれば、インターバル・パーティショニングを使うとよいです。データを均等に分割でき、さらにパーティショニングが必要な場合は、インターバル・ハッシュ・パーティショニングが適しています。もちろん、どちらも当てはまらないデータセットであれば、通常のハッシュ・パーティショニングでも問題ありません。

有効期限ルール

上記で説明したように、有効期限ルールはすべてインターバル・パーティショニングに基づいています。上記で説明したように、有効期限ルールは完全にインターバル・パーティショニングに基づいています。テーブルを作成する際に、有効期限ルールとパーティショニング・ルールに関連する追加情報を追加します。最初の例を見て説明し、テーブルを作成してGridDB CLIで見てみましょう。

CREATE TABLE IF NOT EXISTS pyIntPart (
  date TIMESTAMP NOT NULL PRIMARY KEY,
  value STRING

WITH
(expiration_type='PARTITION',expiration_time=10,expiration_time_unit='DAY')
PARTITION BY RANGE (date) EVERY (5, DAY);

WITHの前はすべて標準的なものですが、タイムスタンプ型は2つの特別な属性を取ることに注意してください: NOT NULLとPRIMARY KEYです。これらは両方とも、インターバル・パーティションド・コレクション・コンテナを作成するために必要です。有効期限と単位を設定するとき、データの行が 「コールド」(検索不能)になり、最終的にディスクから削除される頻度を明示することになります。ここでは単位をDAY`、時間を10に設定しています。つまり、データが10日経過した時点で、データは段階的に削除されることになります。もしこれらの行が個別に期限切れに設定されていればそうなりますが、実際には期限切れのタイプはPARTITIONに設定されています。

簡単に言うと、テーブルpyIntPartのパーティショニング範囲は5日間です。つまり、1月1日から1月6日までのすべての行は、1つのパーティションに入ることになります。パーティショニングが行われるのは、期限切れのデータがどのように処理されるかという部分です。

date value
2024-01-01T00:00:00.000Z 0
2024-01-02T00:00:00.000Z 1
2024-01-03T00:00:00.000Z 2
2024-01-04T00:00:00.000Z 3
2024-01-05T00:00:00.000Z 4
2024-01-06T00:00:00.000Z 5

現在のデータが1月12日だとすると、最初の2行の日付は10日以上前のものなので、すでに削除されていると想像するかもしれないが、データはパーティション全体の中で最も新しいデータ(5日)を使っているので、このデータはすべて1月16日まで存続する。このデータは1月16日まで有効で、その後パーティション全体が段階的に削除されます。

もちろん、異なるルールを設定して、このデータが削除される頻度を調整することもできます。

Pythonの例では、TODAYから開始し、20日前まで追加します。やがてデータが古くなると、GridDBは即座にデータを 「cold 」に移します。その前に、SQLでGridDBサーバーに接続してみましょう。

import jpype
import jpype.dbapi2
from datetime import datetime, timedelta
import pandas as pd


url = "jdbc:gs://127.0.0.1:20001/myCluster/public"
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=./lib/gridstore-jdbc.jar")
conn = jpype.dbapi2.connect(url, driver="com.toshiba.mwcloud.gs.sql.Driver", driver_args={"user": "admin", "password": "admin"})
curs = conn.cursor()

jpypeでは、ローカルのgridstore-jdbc jarファイルを指定し、手動でJVM` を起動する必要があります。(このため、このプロジェクトではJavaが必須の前提条件となっています)。

接続が完了したので、テーブルを作成してデータをインサートしましょう。なお、Interval Hash Partitionedテーブルを作成するセクションもありますが、Interval Partitionedテーブルとコンセプトが非常に似ているため、説明は控えます。

createIntervalPartition = """CREATE TABLE IF NOT EXISTS pyIntPart (
  date TIMESTAMP NOT NULL PRIMARY KEY,
  value STRING
)
WITH
(expiration_type='PARTITION',expiration_time=10,expiration_time_unit='DAY')
PARTITION BY RANGE (date) EVERY (5, DAY);"""
curs.execute(createIntervalPartition)

now = datetime.utcnow()
for x in range (0, 20):
    pyIntPart = "INSERT INTO pyIntPart values ( TO_TIMESTAMP_MS(" + str(now.timestamp()*1000) +"), 'val" + str(x) + "')"
    pyIntHashPart = "INSERT INTO pyIntHashPart values ( TO_TIMESTAMP_MS(" + str(now.timestamp()*1000) +"), 'val" + str(x) + "')"
    #print(pyIntPart)
    #print(pyIntHashPart)
    curs.execute(pyIntPart)
    curs.execute(pyIntHashPart)
    now = now - timedelta(days=1)

curs.execute("SELECT * FROM pyIntPart")
cols = tuple(zip(*curs.description))[0]
df = pd.DataFrame(curs.fetchall(), columns=cols)
print(df)

The results: (now: 2024-03-12 00:47:03.714053)

                      date  value
0  2024-03-02 00:47:03.714  val10
1  2024-03-01 00:47:03.714  val11
2  2024-02-29 00:47:03.714  val12
3  2024-02-28 00:47:03.714  val13
4  2024-02-27 00:47:03.714  val14
5  2024-03-12 00:47:03.714   val0
6  2024-03-11 00:47:03.714   val1
7  2024-03-10 00:47:03.714   val2
8  2024-03-09 00:47:03.714   val3
9  2024-03-08 00:47:03.714   val4
10 2024-03-07 00:47:03.714   val5
11 2024-03-06 00:47:03.714   val6
12 2024-03-05 00:47:03.714   val7
13 2024-03-04 00:47:03.714   val8
14 2024-03-03 00:47:03.714   val9

ここにあるように、2024年3月12日から開始し、20日前のデータを追加しようとしています(単純なforループで、20に達するまで1日ずつ減算しています)。期限切れルールがなければ、pandasのデータフレームにデータを読み込んだときに20行のデータが出力されるはずですが、その代わりに、もちろん、いくつかの行のデータは期限切れとなり、代わりに15行が残ります。この理由はパーティションルールからわかります。CLIでshowcontainerを実行すると、次のようになります:

gs[public]> showcontainer pyIntPart
Database    : public
Name        : pyIntPart
Type        : COLLECTION
Partition ID: 15
DataAffinity: -
Partitioned : true
Partition Type           : INTERVAL
Partition Column         : date
Partition Interval Value : 5
Partition Interval Unit  : DAY
Expiration Type      : PARTITION
Expiration Time      : 10
Expiration Time Unit : DAY

Columns:
No  Name                  Type            CSTR  RowKey
------------------------------------------------------------------------------
 0  date                  TIMESTAMP(3)    NN    [RowKey]
 1  value                 STRING                

Indexes:
Name        : 
Type        : TREE
Columns:
No  Name                  
--------------------------
 0  date

つまり、02/27から03/12までのデータセットは、3つの異なるパーティションにまたがっています。

date
2024-03-08 00:47:03.714
2024-03-09 00:47:03.714
2024-03-10 00:47:03.714
2024-03-11 00:47:03.714
2024-03-12 00:47:03.714

そして

date
2024-03-03 00:47:03.714
2024-03-04 00:47:03.714
2024-03-05 00:47:03.714
2024-03-06 00:47:03.714
2024-03-07 00:47:03.714

最後に

date
2024-02-27 00:47:03.714
2024-02-28 00:47:03.714
2024-02-29 00:47:03.714
2024-03-01 00:47:03.714
2024-03-02 00:47:03.714

02/21から02/26までの日数分のパーティションがもう1つあるが、10日前は03/01なので、最後のパーティションのデータはすべて有効期限外になり、パーティション全体が検索できなくなり、削除される可能性もあります。

結論

この記事を通して、期限切れパーティショニングがどのように機能するのかを説明し、実際にどのように機能するのかをPythonを使ったデモで示しました。期限切れルールを弄ってみて、さらにどう動くか試してみてください。

ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb

Leave a Reply

Your email address will not be published. Required fields are marked *