PythonでNo module named bz2

以下のようにbz2がないと言われるケースがある。

$ python -m gensim.scripts.make_wiki enwiki-latest-pages-articles.xml.bz2 wiki_en_output
/home/taro/.pyenv/versions/2.7.9/bin/python: No module named bz2

Ubuntuでpyenvを利用していれば、

$ sudo apt-get install libbz2-dev
$ pyenv install --force 2.7.9

というようにlibbz2-devをインストールして、Pythonを再度インストールすれば解決する。

pyenvでPython環境を利用する

環境によっては、Pythonが古かったり、しかもそれを更新できなかったりする場合があるかと思うけど、そんなときにpyenvでPython環境を作るとよい。
今回は、Ubuntuに入れる想定で進める。まず、pyenvをcloneする。

$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv

そして、環境変数の設定。Ubuntuでなければ、.bash_profileとかに入れるのが良いでしょう。

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(pyenv init -)"' >> ~/.bashrc

ここで、一度ターミナルを開き直す。
pyenvで利用できるバージョンを確認する。

$ pyenv install -l
Available versions:
  2.1.3
  2.2.3
  2.3.7
  2.4
  2.4.1
  2.4.2
  2.4.3
...

今回は2.7.9を入れる。

$ pyenv install 2.7.9
$ pyenv rehash

インストールしたPythonを利用するように設定する。

$ pyenv versions
* system (set by /home/taro/.pyenv/version)
  2.7.9
$ pyenv global 2.7.9
$ pyenv versions
  system
* 2.7.9 (set by /home/taro/.pyenv/version)

という感じで、環境の準備完了。
Python 2.7系であれば、~/.pyenv/versions/2.7.9/lib/python2.7/site-packages/sitecustomize.pyを作成して

import sys
sys.setdefaultencoding('utf-8')

を記述しておくとエンコーディング周りで悩まされないでよいかも。
あとは、使うモジュールをインストールしておく。(以下は個人的なメモに近いけど…)

pip install elasticsearch
pip install numpy
pip install scipy
pip install matplotlib
pip install pandas
pip install scikit-learn
pip install gensim

Wikipediaのデータをスクロールスキャンする

WikipediaをElasticsearchに取り込むの続き。
いろいろと試していくためには、Elasticsearchに取り込んだWikipediaのデータにアクセスできるようになる必要がある。Elasticsearchで全データにアクセスするためには、ScrollScanでアクセスする。
というわけで、今回はPythonで全データにアクセスしてみる。
事前にpip install ElasticsearchなどでPythonモジュールを利用可能な状況にしておく必要があるが、以下のような.pyを作成する。

# coding: utf-8
from optparse import OptionParser
import sys
from elasticsearch import Elasticsearch
import json
from elasticsearch.exceptions import NotFoundError
def main(argv=sys.argv):
    parser = OptionParser(prog="main.py")
    parser.add_option("--elasticsearch", dest="elasticsearch",
                  help="Elasticsearch", metavar="ES",
                  default="localhost:9200")
    parser.add_option("--index", dest="index",
                  help="Index", metavar="INDEX",
                  default="_all")
    parser.add_option("--source", dest="source",
                  help="Source", metavar="SOURCE",
                  default="{\"query\":{\"match_all\":{}}}")
    (options, args) = parser.parse_args()
    source = json.loads(options.source)
    es = Elasticsearch(hosts=options.elasticsearch)
    response = es.search(index=options.index,
                         scroll='1m',
                         search_type='scan',
                         size=100,
                         body=source)
    scroll_id = response['_scroll_id']
    counter = 0
    while (True):
        try:
            response = es.scroll(scroll_id=scroll_id, scroll='1m')
            if len(response['hits']['hits']) == 0:
                break
            for hit in response['hits']['hits']:
                counter = counter + 1
                if "_source" in hit:
                    if "title" in hit['_source']:
                        print hit['_source']['title']
        except NotFoundError:
            print u"Finished ({0}) documents.".format(counter)
            break
        except:
            print u"Unexpected error: {0}".format(sys.exc_info()[0])
            break
    return 0
if __name__ == "__main__":
    sys.exit(main())

上記の例ではスクロールで_sourceのtitleデータを出力している。
NotFoundErrorのエラーで止めるのも微妙だけど、何か良い方法があるのかしら…。
実行は

$ python title.py --index jawiki-pages-articles

という感じで実行すれば、タイトルが出力されていく。
というわけで、そのあたりのコードをいじればいろいろできる感じかな。