Aerospike で aql を使ってデータ操作を試してみる

## 概要
Aerospike では [aql](http://www.aerospike.com/docs/tools/aql/) (*Aerospike Query Language*) と呼ばれる SQL に近いコマンドラインインターフェースがあります。
aql を使って CRUD処理などのデータ操作を試してみます。

## 前提
Aerospike インストール済み環境
[Aerospike を Ubuntu 15.04 にインストールする手順](http://qiita.com/amotz/items/00f001529b8f587b09c2)

## 用語

Aerospike と RDB は用語が違うので、混乱しないようにまとめておきます。

| Aerospike | RDB | 
|:-----------|:------------|
| Namespace  |Database     |
| Set     |Table    |
| Record       |Row     |
| Bin |Column      |

参考：[Aerospike Data Model](http://www.aerospike.com/docs/architecture/data-model.html)

## aql 起動
Aerospike のサービスが起動していることを確認し、以下のコマンドを実行します。

```bash
$ aql
```

```shell-session
Aerospike Query
Copyright 2013-2015 Aerospike. All rights reserved.

aql>
```

aql のプロンプトが表示されます。

## CRUD

以下のような構成の **fruits** という Set を aql で作ってみます。

| PK(primary key) | Name | Price | Description | 
|:-----------|:------------|:------------|:------------|
| 1  | Ringo     | 100 | from Aomori |
| 2  | Mikan    | 50 | from Wakayama |
| 3  | Nashi     | 150 | from Tottori |
| 4  | Dragon Fruit | 300 | from Ishigaki-island |

なお、Namespace は **test** とします。
※Aerospike インストール時にデフォルトで作成されています。

### データ生成
insert文でデータを生成します。
insert前にcreate table的な処理は不要です。

```sql
aql> INSERT INTO test.fruits (PK, Name, Price, Description) VALUES (1, 'Ringo', 100, 'from Aomori')
```

```shell-session
OK, 1 record affected.
```

同様に以下のレコードを追加します。

```sql
aql> INSERT INTO test.fruits (PK, Name, Price, Description) VALUES (2, 'Mikan', 50, 'from Ehime')
aql> INSERT INTO test.fruits (PK, Name, Price, Description) VALUES (3, 'Nashi', 150, 'from Tottori')
aql> INSERT INTO test.fruits (PK, Name, Price, Description) VALUES (4, 'Dragon Fruit', 300, 'from Ishigaki-island')
aql> INSERT INTO test.fruits (PK, Name, Price, Description) VALUES (5, 'starfruit', 300, 'from Miyako-island')
```

### データ更新
update文は無いため、insert文で PK を指定し、データを更新します。

```sql
aql> INSERT INTO test.fruits (PK, Description) VALUES (2, 'from Wakayama')
```

```shell-session
OK, 1 record affected.
```

### データ削除
delete文でデータを削除します。PK を指定する必要があります。

```sql
aql> DELETE FROM test.fruits WHERE PK = 5
```

```shell-session
OK, 1 record affected.
```

### データ読み取り
select文でデータを参照します。

```sql
aql> SELECT * FROM test.fruits
```

```shell-session
+----------------+-------+------------------------+
| Name           | Price | Description            |
+----------------+-------+------------------------+
| "Dragon Fruit" | 300   | "from Ishigaki-island" |
| "Nashi"        | 150   | "from Tottori"         |
| "Mikan"        | 50    | "from Wakayama"        |
| "Ringo"        | 100   | "from Aomori"          |
+----------------+-------+------------------------+
4 rows in set (0.014 secs)
```

意図した通りにデータを準備し、参照することができました。
#### 参照結果に PK が表示されていない
Aerospike では、[キーをハッシュ化して利用](http://www.aerospike.com/docs/architecture/data-model.html#keys-and-digests)するため、デフォルトでは Primary Key をそのまま参照することができません。
キーを参照するには、[キーをそのまま保存するオプション](https://www.aerospike.com/apidocs/java/com/aerospike/client/policy/Policy.html#sendKey)を利用する必要があります~~が、 aql 単体ではそのような機能はないようです~~ 。 
**（2016/6/30 追記）**
[ver.3.8.2.2](http://www.aerospike.com/download/server/notes.html#3.8.2.2) 以降、aql起動時に ```-K``` オプションを指定することで、キーをそのまま保存できるようです。

### データ読み取り（Bin単位で絞込）
Bin単位でwhere句による絞込を行うには、別途インデックスを作成する必要があります。
Name, Price の Bin にそれぞれ **fruit_name_index**, **fruit_price_index** というインデックスを作成してみます。

```sql
aql> CREATE INDEX fruit_name_index ON test.fruits (Name) STRING
```

```shell-session
OK, 1 index added.
```

```sql
aql> CREATE INDEX fruit_price_index ON test.fruits (Price) NUMERIC
```

```shell-session
OK, 1 index added.
```

インデックス作成後、絞り込みを実行できます。

```sql
aql> SELECT * FROM test.fruits WHERE Name = 'Nashi'
```

```shell-session
+---------+-------+----------------+
| Name    | Price | Description    |
+---------+-------+----------------+
| "Nashi" | 150   | "from Tottori" |
+---------+-------+----------------+
1 row in set (0.000 secs)
```


```sql
aql> SELECT * FROM test.fruits WHERE Price BETWEEN 0 and 120
```

```shell-session
+---------+-------+-----------------+
| Name    | Price | Description     |
+---------+-------+-----------------+
| "Ringo" | 100   | "from Aomori"   |
| "Mikan" | 50    | "from Wakayama" |
+---------+-------+-----------------+
2 rows in set (0.000 secs)
```

## その他の操作

### Namespaceリスト
Namespace のリストを表示します。

```sql
aql> SHOW NAMESPACES
```

```shell-session
+------------+
| namespaces |
+------------+
| "test"     |
| "bar"      |
+------------+
2 rows in set (0.001 secs)
```

### Setリスト
すべての Set を表示します。

```sql
aql> SHOW SETS
```
```shell-session
+-----------+------------------+----------------+-------------------+----------------+---------+----------+------------+
| n_objects | disable-eviction | set-enable-xdr | stop-writes-count | n-bytes-memory | ns_name | set_name | set-delete |
+-----------+------------------+----------------+-------------------+----------------+---------+----------+------------+
| 4         | "false"          | "use-default"  | 0                 | 275            | "test"  | "fruits" | "false"    |
+-----------+------------------+----------------+-------------------+----------------+---------+----------+------------+
1 row in set (0.000 secs)
OK
```

### Binリスト
すべての Bin を表示します。

```sql
aql> SHOW BINS
```

```shell-session
aql> show bins
+-------+---------------+-------+-----------+
| quota | bin           | count | namespace |
+-------+---------------+-------+-----------+
| 32768 | "Name"        | 3     | "test"    |
| 32768 | "Price"       | 3     | "test"    |
| 32768 | "Description" | 3     | "test"    |
+-------+---------------+-------+-----------+
3 rows in set (0.000 secs)
OK

```

### Indexリスト
すべての Index を表示します。

```sql
aql> SHOW INDEXES
```

```shell-session
+--------+---------+-----------+----------+-------+---------------------+---------+------------+-----------+
| ns     | bin     | indextype | set      | state | indexname           | path    | sync_state | type      |
+--------+---------+-----------+----------+-------+---------------------+---------+------------+-----------+
| "test" | "Price" | "NONE"    | "fruits" | "RW"  | "fruit_price_index" | "Price" | "synced"   | "NUMERIC" |
| "test" | "Name"  | "NONE"    | "fruits" | "RW"  | "fruit_name_index"  | "Name"  | "synced"   | "STRING"  |
+--------+---------+-----------+----------+-------+---------------------+---------+------------+-----------+
2 rows in set (0.000 secs)
OK
```

## 参考
[Aerospike Tools & Utilities - Aerospike Query Language](http://www.aerospike.com/docs/tools/aql/)