Jupyter NotebookとMySQL X DevAPI

Pythonのコードを試すのに便利なJupyter Notebookを使って、Connector/PythonからMySQL X DevAPIを試す環境を作ってみました。Jupyter Notebookの利用には Anaconda に含まれるPythonとJupyter を使うことが強く推奨(strongly recommend)されています。
https://jupyter.org/install.html
ちなみにAnacondaは「データサイエンス向けに作成された Pythonパッケージ」と Python.jp で紹介されています。WindowsでもmacOSでもGUIインストーラでさくさくインストールできます。

AnacondaへのConnector/Pythonのインストール

Anaconda.orgにパッケージをインストールする場合は conda install コマンドを使うとされています。
https://conda.io/docs/user-guide/tasks/manage-pkgs.html#installing-packages-from-anaconda-org
ところがAnaconda.orgには、標準のanacondaチャンネルではConnector/Python 2.0.4が、その他のチャンネルでも8.0系にバージョン番号ポリシーが変更される前の2.2.3が最新という状態で、Connector/Python 8.0をインストールすることができません。
https://anaconda.org/anaconda/mysql-connector-python

そこでnon-condaパッケージのインストールという手順を使います。
https://conda.io/docs/user-guide/tasks/manage-pkgs.html#installing-non-conda-packages
pipパッケージ管理ツールでmysql-connector-pythonパッケージをバージョン番号を指定して、Connector/Python 8.0.6をインストールします。
https://pypi.python.org/pypi/mysql-connector-python

# Anacondaの仮想環境の確認
sakila:~ sakila$ conda info --envs
# conda environments:
#
root                  *  /Users/sakila/anaconda3

# 仮想環境rootをアクティベート
# Windowsではこのコマンドでエラーなくアクティベートできた
# macOSではエラーになるのでエラーメッセージのsource付きコマンドを実行
sakila:~ sakila$ activate root
Error: activate must be sourced. Run 'source activate envname'
instead of 'activate envname'.

sakila:~ sakila$ source activate envname

CondaEnvironmentNotFoundError: Could not find environment: envname .
You can list all discoverable environments with `conda info --envs`.

sakila:~ sakila$ source activate root

# pipコマンドでConnector/Python 8.0.6をインストール
(root) sakila:~ sakila$ pip install mysql-connector-python==8.0.6
Collecting mysql-connector-python==8.0.6
  Downloading mysql_connector_python-8.0.6-cp36-cp36m-macosx_10_12_x86_64.whl (3.2MB)
    100% |======================================| 3.2MB 413kB/s 
Installing collected packages: mysql-connector-python
Successfully installed mysql-connector-python-8.0.6

これでJupyter NotebookからConnector/Python 8.0.6を利用できるようになりました。

MySQL 8.0.4のインストールとX Pluginの登録

MySQL 8.0.4に関してはWindowsはZIP, LinuxmacOSはTARを展開するのが手っ取り早いです。ちなみにWindows用のMySQL Installerは8.0.4が用意されていませんでした。--initializeまたは--initialize-insecureなどで初期化し、起動しておきます。

X DevAPIをサポートするためにX Pluginを登録します。
https://dev.mysql.com/doc/refman/8.0/en/document-store-setting-up.html
MySQL Shellがインストールしてあれば下記のコマンドでX Pluginが登録できます。

mysqlsh -u user -h localhost --classic --dba enableXProtocol

MySQL Shellがなければmysqlクライアントからサーバーに接続し、下記のコマンドを実行します。

mysql> INSTALL PLUGIN mysqlx SONAME 'mysqlx.so';

なおWindows上ではmysqlx.soだとファイルが見つからないためエラーとなるので、mysqlx.dllに変更します。

X DevAPIの動作確認のためJSONデータを含んだサンプルデータベースworld_xデータベースを下記からダウンロードし、展開してロードしておきます。
https://dev.mysql.com/doc/index-other.html

mysql -uroot < /foo/bar/world_x-db/world_x.sql 

Jupyter Notebookからの動作確認

Anaconda Navigatorを起動しJupyter Notebookを選択します。起動直後のJupyter NotebookはWebブラウザ上にフォルダの一覧が表示される状態となっています。必要に応じてノート作成のフォルダを作成するか選択し、その後、画面右上のNewのプルダウンからPython 3を選択し、Notebookを新規作成します。
NotebookではIn [1]:の横のテキストボックスにPythonのコードを記載し、Shift + Enterで実行することができます。

まずは動作確認を兼ねて、Connector/Pythonのリファレンスマニュアルのサンプルコードを組み合わせて、稼働中のMySQLサーバーのバージョンをVERSION()関数で確認してみます。

from mysql.connector import (connection)

cnx = connection.MySQLConnection(user='root', host='127.0.0.1')
cur = cnx.cursor(buffered=True)
cur.execute("SELECT VERSION()")
print(cur.fetchone())
cur.close()
cnx.close()

続いてSQLを変更して実際のデータとして先ほどインポートしたworld_xスキーマのcountryinfoテーブルのデータを取得してみます。このテーブルはCollectionとなるテーブル構造(JSON型の列とJSONドキュメント内の_id要素を抽出したGenerated Columnの_id列のみ、_id列は主キー)となっています。

mysql> desc world_x.countryinfo;
+-------+-------------+------+-----+---------+------------------+
| Field | Type        | Null | Key | Default | Extra            |
+-------+-------------+------+-----+---------+------------------+
| doc   | json        | YES  |     | NULL    |                  |
| _id   | varchar(32) | NO   | PRI | NULL    | STORED GENERATED |
+-------+-------------+------+-----+---------+------------------+
2 rows in set (0.02 sec)

from mysql.connector import (connection)

cnx = connection.MySQLConnection(user='root', host='127.0.0.1')
cur = cnx.cursor(buffered=True)
cur.execute("SELECT * FROM world_x.countryinfo")
print(cur.fetchone())
cur.close()
cnx.close()

Jupyter NotebookからのX Dev APIでのアクセス

先ほどと同様に、リファレンスマニュアルのサンプルコードを少し変更して、SQL文でもアクセスしたCollectionであるcountryinfoテーブルにX Dev APIでアクセスしてみます。ここでは10ドキュメント(=10行)取得して配列docに格納、その先頭レコードのうちName要素を取得して表示しています。インポート対象パッケージはmysqlxになっています。

import mysqlx

# Connect to server on localhost
session = mysqlx.get_session({
    'host': 'localhost',
    'port': 33060,
    'user': 'root',
    'password': ''
})

schema = session.get_schema('world_x')

# Use the collection 'my_collection'
collection = schema.get_collection('countryinfo')

# Specify which document to find with Collection.find()
result = collection.find().limit(10).execute()

# Print document
docs = result.fetch_all()
print('Name: {0}'.format(docs[0]['Name']))

session.close()

ちなみにMySQLサーバーのユーザーにパスワードがない場合、ポート3306を使用するMySQL標準プロトコルの例では接続情報にパスワードに関する表記はなくても問題ありませんが、X Dev APIの場合は空文字を指定しないと接続時にエラーとなります。