Python から MapR-DB JSON にアクセスしてみる

MapRアドベントカレンダー[初日](https://qiita.com/bigt23/items/c7026fc1fe7b186290d7)に続き、今回は Python から MapR-DB アクセスしてみます。

# 準備

準備にあたっては以下をインストールする必要があります

* Python 3 and Python 3 devel

今回の環境はCentOS 6.8 だったのでPython3を別途インストールする必要がありました。
お好みの方法でインストールしてください。

* Maven

```shell-session
# wget http://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo -O /etc/yum.repos.d/epel-apache-maven.repo
# sed -i s/\$releasever/6/g /etc/yum.repos.d/epel-apache-maven.repo
# yum install -y apache-maven
```

* GCC (for C and C++)

```shell-session
# yum install gcc gcc-c++
```

* mapr-client

今回はクラスタ環境からアクセスしてみます。
クライアントノードから実行する場合はmapr-clientパッケージをインストールして下さい

```shell-session
# yum install mapr-client
```

* maprdb ライブラリ

ここまでインストールしたらmaprdbライブラリをpipで入れましょう

```shell-session
# pip3 install maprdb
```

# Document and Demo

Python バインディングに関するドキュメントは[こちら](https://pypkg.com/pypi/maprdb/f/spec.md)になります。
また、デモコードは[こちら](https://github.com/mapr-demos/maprdb_python_examples)にまとまっています。
この辺を参考にコードを動かしてみましょう

# Let's play

Rubyのときと同じく、テーブルを作成しデータを挿入、更新、削除してみます。

```py3
from maprdb import connect, Document, Mutation
connection = connect()
table_path = "/user/mapr/db/python-binding"
table = None

# テーブル作成。既に存在している場合はget()
if connection.exists(table_path):
    table = connection.get(table_path)
else:
    table = connection.create(table_path)

# ドキュメント作成
document1_key = "白鵬"
document2_key = "日馬富士"
document1 = Document({'_id':document1_key,
                      'name':'ムンフバティーン・ダワージャルガル',
                      '四股名':'白鵬 翔',
                      'place':['両国', '名古屋'],
                      'other':{'ちゃんこ':'味噌', 'まわし':'黒'},
                      'count': 7})

document2 = Document({'_id':document2_key,
                      'name':'ダワーニャミーン・ビャンバドルジ',
                      '四股名':'安馬',
                      'place':['九州'],
                      'other': {'ちゃんこ':'カレー', 'まわし':'赤'},
                      'count': 7})


# 挿入
table.insert_or_replace(document1)
table.insert_or_replace(document2)
table.flush()

# 確認
print("\n挿入後データ確認\n")
for item in table.find():
   print(item)

# Mutationオブジェクト作成
mutation1 = Mutation()
mutation1.increment('count', 33)

mutation2 = Mutation()
mutation2.append('四股名', ' 公平')
mutation2.append('place', ['大阪'])

# 更新
table.update(document1_key, mutation1)
table.update(document2_key, mutation2)
table.flush()

# データ確認
print("\n更新後データ確認\n")
for item in table.find():
   print(item)

# 削除
table.delete(document2_key)
table.flush()

print("\n削除後データ確認\n")
for item in table.find():
   print(item)

connection.delete(table_path)
```

さて実行してみます

```shell-session
$ python3 test.py
挿入後データ確認

{'count': 7, '_id': '日馬富士', '四股名': '安馬', 'other': {'まわし': '赤', 'ちゃんこ': 'カレー'}, 'name': 'ダワーニャミーン・ビャンバドルジ', 'place': ['九州']}
{'count': 7, '_id': '白鵬', '四股名': '白鵬 翔', 'other': {'まわし': '黒', 'ちゃんこ': '味噌'}, 'name': 'ムンフバティーン・ダワージャルガル', 'place': ['両国', '名古屋']}

更新後データ確認

{'count': 7, '_id': '日馬富士', '四股名': '安馬 公平', 'other': {'まわし': '赤', 'ちゃんこ': 'カレー'}, 'name': 'ダワーニャミーン・ビャンバドルジ', 'place': ['九州', '大阪']}
{'count': 40, '_id': '白鵬', '四股名': '白鵬 翔', 'other': {'まわし': '黒', 'ちゃんこ': '味噌'}, 'name': 'ムンフバティーン・ダワージャルガル', 'place': ['両国', '名古屋']}

削除後データ確認

{'count': 40, '_id': '白鵬', '四股名': '白鵬 翔', 'other': {'まわし': '黒', 'ちゃんこ': '味噌'}, 'name': 'ムンフバティーン・ダワージャルガル', 'place': ['両国', '名古屋']}
```

期待通り動いていますね。

ドキュメントにはConditionクラスの説明もあります。
これを利用することで取得するデータへのフィルタを行うことが出来るようです。
以下のように試してみます。

```py3
from maprdb import connect, Document, Mutation, Condition
connection = connect()
table_path = "/user/mapr/db/python-binding"
table = None

# テーブル作成。既に存在している場合はget()
if connection.exists(table_path):
    table = connection.get(table_path)
else:
    table = connection.create(table_path)

# ドキュメント作成
document1_key = "白鵬"
document2_key = "日馬富士"
document1 = Document({'_id':document1_key,
                      'name':'ムンフバティーン・ダワージャルガル',
                      '四股名':'白鵬 翔',
                      'place':['両国', '名古屋'],
                      'other':{'ちゃんこ':'味噌', 'まわし':'黒'},
                      'count': 40})

document2 = Document({'_id':document2_key,
                      'name':'ダワーニャミーン・ビャンバドルジ',
                      '四股名':'安馬',
                      'place':['九州'],
                      'other': {'ちゃんこ':'カレー', 'まわし':'赤'},
                      'count': 7})


# 挿入
table.insert_or_replace(document1)
table.insert_or_replace(document2)
table.flush()

# 確認
print("\n挿入後データ確認\n")
for item in table.find():
   print(item)

# Condition作成
c = Condition({
        '四股名':'安馬'
    })

print(table.find(c, columns=None))

connection.delete(table_path)
```

実行してみます

```
$ python3 test2.py
挿入後データ確認

{'name': 'ダワーニャミーン・ビャンバドルジ', 'place': ['九州'], '四股名': '安馬', 'count': 7, 'other': {'まわし': '赤', 'ちゃんこ': 'カレー'}, '_id': '日馬富士'}
{'name': 'ムンフバティーン・ダワージャルガル', 'place': ['両国', '名古屋'], '四股名': '白鵬 翔', 'count': 40, 'other': {'まわし': '黒', 'ちゃんこ': '味噌'}, '_id': '白鵬'}
Traceback (most recent call last):
  File "test2.py", line 45, in <module>
    print(table.find(c, columns=None))
  File "/usr/lib/python3.3/site-packages/maprdb/utils.py", line 98, in wrapper
    ret = f(*args, **kwargs)
TypeError: find() got multiple values for argument 'columns'
```

コケてしまいました。。。
同様の報告がgithubにも[あがっています](https://github.com/mapr-demos/python-bindings/issues/15)ね。
早く修正されることを願います。

以上３日目でした。