JavaでRocksDBを使用してみる

# RockDBとは
Key-Valueのデータ形式（バイト配列）を保持するデータベース。
C++で作られており、JavaからもJNIで使用できる。
ただし、JavaのAPIはC++のAPIに追いついていないとのこと。

Wiki
https://ja.wikipedia.org/wiki/RocksDB

# 使い方
以下に簡単な使用方法を記載します。
詳細は公式のドキュメントを参照してください。

https://github.com/facebook/rocksdb/wiki/RocksJava-Basics

## Maven
以下のライブラリを使用します。
RocksDbのみを使用する場合、rocksdbjniのみでOK。
シリアライズ、デシリアライズのためにkryoを追加しています。

```xml
		<dependency>
			<groupId>org.rocksdb</groupId>
			<artifactId>rocksdbjni</artifactId>
			<version>6.0.1</version>
		</dependency>
		<dependency>
            <groupId>com.esotericsoftware</groupId>
            <artifactId>kryo</artifactId>
            <version>3.0.1</version>
        </dependency>
```

## オープン・クローズ
クローズ用のメソッドもあるが、try-with-resourcesの使用を推奨しているので、従いましょう。
openにはDB保存先のパスを指定する必要があります。以下のように指定するとプロジェクト直下にDB用のフォルダが作成されます。

```java
		try (RocksDB rocksDb = RocksDB.open("sample")) {
                   // ここに処理を書く
        }
```

## 読み込み、書き込み、削除
基本的なAPIの使用例です。
読み込みはget、書き込みはput、削除はdeleteです。
その他、全件取得(newIterator)、範囲削除(deleteRange)、複数取得(multiGetAsList)の使用例を記載しています。

```java
	public void execute() {

		// RocksDBをOpenする。openにはDB保存先を指定する（下記の指定を行うとプロジェクト直下に作成される）
		try (RocksDB rocksDb = RocksDB.open("sample")) {

			// Kryoを使用してシリアライズ
			byte[] binaryKey = serialize("key");
			byte[] binaryValue = serialize("Value");

			// Key、Valueを指定してRocksDBにput（API#put)
			// 重複したKeyを登録してもエラーとならず、上書きするだけ
			rocksDb.put(binaryKey, binaryValue);
			rocksDb.put(binaryKey, binaryValue);

			// シリアライズしたKeyを使用して、RocksDBから取得（API#get)
			try (Input input = new Input(rocksDb.get(binaryKey))) {
				System.out.println(kryo.readObject(input, String.class));
			}

			// Keyを指定してRockDBから削除（API#delete)
			rocksDb.delete(binaryKey);
			if (null == rocksDb.get(binaryKey)) {
				System.out.println("取得できません");
			}

			for (int i = 0; i < 10; i++) {
				// Kryoを使用してシリアライズ
				byte[] tempBinaryKey = serialize("key" + String.valueOf(i));
				byte[] tempBinaryValue = serialize("Value"+ String.valueOf(i));

				// Key、Valueを指定してRocksDBにput
				rocksDb.put(tempBinaryKey, tempBinaryValue);
			}

			// RocksDB内のすべてのデータ取得（API#newIterator)
			System.out.println("全Entry取得");
			RocksIterator iterator = rocksDb.newIterator();
			iterator.seekToFirst();
			while (iterator.isValid()) {
				try (Input input = new Input(iterator.key())) {
					System.out.println(kryo.readObject(input, String.class));
				}
				iterator.next();
			}

			// RocksDB内をキーの範囲を指定して削除(API#deleteRange)
			// beginKeyに指定〜EndKeyの直前までが削除される
			rocksDb.deleteRange(serialize("key0"), serialize("key8"));
			System.out.println("範囲削除key0-key7");
			RocksIterator iterator2 = rocksDb.newIterator();
			iterator2.seekToFirst();
			while (iterator2.isValid()) {
				try (Input input = new Input(iterator2.value())) {
					System.out.println(kryo.readObject(input, String.class));
				}
				iterator2.next();
			}

			// RocksDB内複数取得(#multiGetAsList)
			System.out.println("複数取得");
			List<byte[]> binaryKeyList = new ArrayList<>();
			binaryKeyList.add(serialize("key8"));
			binaryKeyList.add(serialize("key9"));
			List<byte[]> binaryValueList = rocksDb.multiGetAsList(binaryKeyList);
			for (byte[] binary:binaryValueList) {
				try (Input input = new Input(binary)) {
					System.out.println(kryo.readObject(input, String.class));
				}
			}

		} catch (RocksDBException e) {
			throw new RuntimeException(e);
		}
	}

	private byte[] serialize(String str) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try (Output output = new Output(baos)) {
			kryo.writeObject(output, str);
		}
		return baos.toByteArray();
	}
```

## どんなときに使う？
ライブラリを導入するだけで使用できるため、RDBを使用するまでも行かないけど、
データの永続化が必要な場面で活躍すると思います。


# 参考
https://github.com/EsotericSoftware/kryo
https://github.com/facebook/rocksdb/wiki/RocksJava-Basics