Filemaker to Python (4) - パターン検索

とりあえず文字化けというか文字が途切れる問題は回避でき、Filemakerのデータベースにアクセスする手順は整ったと言えそうです。Filemaker ODBCドライバ経由で使用できるSQLについては、この資料の中に書いてあります。ただ、今回は中国語の単語のデータベースにアクセスするのが目的で、Python側に持ってきたデータをNLTKの枠組みでいじるので、ODBC側にそこまで複雑なSQLを発行する必要はありません。ただ、パターン検索ぐらいは使うと思うので動作検証してみましょう。

パターン検索を試す

まずはお約束の部分。

>>> import pyodbc
>>> cxcn = pyodbc.connect('DSN=CWord;UID=xxxxxx;PWD=xxxxxxxxxxx')
>>> cursor = cxcn.cursor()

中国語にありがちな、"子"で終わる単語を探してみましょう。

>>> cursor.execute("select Word, Pinyin from CWordsDB where CWordsDB.Word like '%子'")
<pyodbc.Cursor object at 0x102716b10>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
小圏子 xiao3 quan1 zi
寨子 zhai4 zi
汉子 han4 zi
盘子 pan2 zi
积极分子 ji1 ji2 fen1 zi3
钉子 ding1 zi
钻空子 zuan1 kong4 zi
不入虎穴,焉得虎子 bu2 ru4 hu3 xue2 yan1 de2 hu3 zi3
包子 bao1 zi?
杯子 bei1 zi
被子 bei4 zi?
....
桔子 ju2 zi
日子 ri4 zi

ピンインの後ろに'?'が付いているのはソースデータ側(Filemaker)の問題です。後述しますが、これはファイルメーカー側で直接データを修正することにします。修正後にもう1回SQLを発行すれば、変更後のデータを拾ってくれるようです。

もう1パターン、(あまり数は多くないと思いますが)比較の意味で"子"で始まる単語を探してみましょう。

>>> cursor.execute("select Word, Pinyin from CWordsDB where CWordsDB.Word like '子%'")
<pyodbc.Cursor object at 0x102716b10>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
子公司 zi3 gong1 si1
子弹 zi3 dan4
子孙 zi3 sun1

where句のlikeのところを弄っただけです。予想通りあまり数は多くありませんが、3つほどありましたね。ちなみに「子弹」は弾丸のことです。

もう少しだけ複雑な検索

今度は、likeのところを'%子%'で検索してみましょう。

>>> cursor.execute("select Word, Pinyin from CWordsDB where CWordsDB.Word like '% 子%'")
<pyodbc.Cursor object at 0x102716b10>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin                                              
... 
小圏子 xiao3 quan1 zi
寨子 zhai4 zi
汉子 han4 zi
盘子 pan2 zi
望子成龙 wang4 zi3 cheng2 long2
积极分子 ji1 ji2 fen1 zi3
钉子 ding1 zi
钻空子 zuan1 kong4 zi
电子邮件 dian4 zi3 you2 jian4
子公司 zi3 gong1 si1
不入虎穴,焉得虎子 bu2 ru4 hu3 xue2 yan1 de2 hu3 zi3
....
日子 ri4 zi
子孙 zi3 sun1

真ん中に'子'がある単語だけが選ばれるのかなと思いましたが、それら(望子成龙, 电子邮件)に加えて、これまで見てきた'子'ではじまるもの、'子'で終わるものも選択されています。

ここは、とりあえず「ふーん」でスルーしておきます。

今度はピンインを使っての実験です。bei ziという発音の単語を探してみます。今回はbeiの声調は問わずに選ぶのが目的です。

>>> cursor.execute("select Word, Pinyin from CWordsDB where CWordsDB.Pinyin like 'bei%zi'")
<pyodbc.Cursor object at 0x102716b10>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin                                              
... 
杯子 bei1 zi

ん?「被子」も出てくることを期待していたのですが。これは、先ほど述べたように、Filemaker側の元データにおいて、'bei4 zi?'というように不要なクエスチョンマークが付いていたからと思われます。なので、Filemaker側で元データを修正して、もう1回SQLを発行します。

>>> cursor.execute("select Word, Pinyin from CWordsDB where CWordsDB.Pinyin like 'bei%zi'")
<pyodbc.Cursor object at 0x102716b10>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin                                              
... 
杯子 bei1 zi
被子 bei4 zi

出てきましたね。

なぜこの実験が必要か

今回は語学学習の単語DBを材料にしているので、実はODBC側でそこまで込み入った条件のSQLを発行してデータを絞り込む必要はありません。というのも、単語DBは自分で学習した単語が入っているだけなので、この先どんなに単語数が増えてもせいぜい1万語前後にしかならないでしょう。なので、DB全体をPython側で読み込んで、処理してもそれほどマシンに負荷が掛かるとは考えていません。

とは言え、Python自体も処理速度は決して速くないので、大容量のデータ処理には向かないと言われています。今後、大きな別の大きなデータを扱うような場面に遭遇したときには、必要な処理に対してどこまでデータを読み込む(絞り込む)のかというのは、意外に大事になるかも知れません。

その場合は、DBもFilemakerを使うという選択にはならないと思いますが(笑)

おまけのおまけ

ここまで書いてきて、SQLが空振りに終わったときにはどうなるかという挙動を確認するのを忘れていたので、最後に付け加えておきます。

>>> cursor.execute("select Word, Pinyin from CWordsDB where CWordsDB.Pinyin like 'xxxxxxx'")
<pyodbc.Cursor object at 0x102716b10>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin                                              
... 
>>> rows
[]

エラーが吐かれるのではなく、空っぽのリストが返るようです。この方がコーディングとしては扱いやすいですよね。