Hatena::ブログ(Diary)

そこはかとなく書くよ。

2012-02-17

Kindle4

ちょっと前になりますが、Kindle4買いました。アメリカから。まさかその一週間後に日本で展開するという報道があるとは…まあ、Amazon.comのアカウントが移せればいいんですけどね。

f:id:rudi:20120202221915j:image

写真はSphinxで書きだしたePubファイルをCalibreでmobiに変換してkindleに送ったものです。全然問題ありませんね。

nook touchと同じページですので、比較してみるといいと思います。あんまり変わらないですが、やはり日本語がきちんと出るのはKindleの方です。

さよなら、nook…君もroot取った後にrebootしてちゃんと動いてれいればすばらしかったよ…

2012-01-06

Tinkererを使ってbitbucketでblogはじめました

TinkererSphinxを利用して作られたblogツールです。Sphinxを使っていますのでreStructuredText形式で書くことができます。また、blockdiagをはじめとするSphinxの豊富な拡張機能を使うことができます。

今回はtinkererで作成したblogをbitbucketでホスティングしてみます。

bitbucketでのホスティング

bitbucketでは <username>.bitbucket.org という名前のレポジトリを作成し、そこにindex.htmlファイルを置くことでwebページのホスティングができます。これは普通のレポジトリですので、push/pullできますし、履歴管理も出来ます。

そして、実はこのレポジトリはprivateでも構わないのです。privateにすることで、draftなどを隠すことができます。あ、githubと違ってbitbucketはprivateレポジトリが作りたい放題です。

tinkererを実行

さて、実際にblogを書いてみましょう。

その前に、bitbucketで以下のレポジトリを作成します

  • <username>.bitbucket.org (private レポジトリ)

あとはtinkererを実行します

  % mkdir blog
  % cd blog
  % tinker -s  ## ファイルができる
  % vi conf.py
  (タイトルなどを設定する)
  % tinker -p "first post"
  (投稿する)
  % vi 2012/01/04/first_post.rst
  (適当に書く)
  % tinker -b   ## build

これでblog/html以下にhtmlファイルが生成されます。

次に普通にレポジトリを作成しましょう。

  % hg init
  % vi .hg/hgrc

    [paths]
    default=ssh://hg@bitbucket.org/<username>/<username>.bitbucket.org

  % hg add .
  % hg commit -m "first post"
  % hg push

これで <username>.bitbucket.org でtinkererによるblogが出来ました。 http://<username>.bitbucket.org にアクセスしてみてください。

あとは

  • % tinker -p "なにか"

でページを作成・編集してから

  • % tinker -b

でhtmlを生成し、add、commit、pushをすれば更新できます。また、

  • % tinker -d "draft"

でdraftsディレクトリ以下に下書きを作成することも出来ます。

注意点

bitbucketによるホスティングではindexは禁止されているのでdrafts以下は見えません。privateレポジトリなのでレポジトリに他の人がアクセスすることもできません。しかし、直接URLを指定することでファイルの取得ができてしまいます。

そのため、例えばconf.pyなどはほぼ公開と同じようになってしまいます。また、drafts以下のファイルもファイル名が分かってしまうと取得できてしまいます。

実例とbitbucketの注意点

というわけで、英語ブログをはじめました。

http://rrudi.bitbucket.org

ぼくの普段使っているbitbucketのアカウントはr_rudiなのですが、ホスティングする際にこのアンダースコアが問題になってしまいました。URL的にだめみたいです。twitterに投稿しようとしてできなくて悩みました。アンダースコアはRFC 2396ではOKなような気がするのですが、あんまり詳しく調べていません。

追記

blog/html/index.html へのリダイレクトですが、tinker -s で初期設定をtinkererが吐き出した時に一緒にトップディレクトリにblog/html/index.html へのリダイレクトを行うindex.htmlが吐き出されます。


追記その2

conf.pyとかはダウンロードできちゃうよ、って書きましたけど、よく考えればブランチを切ればいいんでした。

  • default
    • 公開用ブランチ。index.htmlとblog以下だけ含まれている
  • drafts
    • 書き用ブランチ。その他のが全部含まれている。

としておいて、普段はdraftsブランチで書いておいて、公開する時にmergeすればいいんですね。

2012-01-04

Army of Darkness Defense

正月は「いまさらかよ」と言われそうですが、iPhoneアプリのArmy of Darkness Defenseをやってました。いや、かなりおもしろいわこれ。

初回プレイは

  • Boomstick + Catapult
  • Armored Guard + Arthur

でwave 50をクリア。Boomstickは範囲攻撃+再使用までの時間が短いので結構使えます。

次は

  • Magic Words + Deathcoaster
  • Horseman + Arthur + Archer

でクリアした後、EndlessモードでHorsemanをLv Maxまで上げて20体ぐらい出すと終わらなくなるというのを確認しました。

最後に

  • Boomstick + Deathcoaster
  • Peasant + swordboy

でLv50までクリアしました。

実はPeasantはやればできる子で、Lv Max(こいつだけLv11まで上がる)に上げてひたすら生産するだけでLv49までは勝てたりします。最初にちょっとironを貯めておいてwisemanも出しておくとよりいいかもしれません。ただ、Lv50はラスボスの攻撃力が高いのでArthurを出す必要と、Deathcoasterでがつんと削る必要とがありました。

最終的に全52個のarchivementsを全て集めました。いえい。

なぜか最終面だけ異様に難しいとかよくあるんですが、これはそういうこともなく、いろいろな遊び方ができるので非常に楽しめました。オススメ。

2011-12-15

multicornを使ってPythonでfdwを実装する

今の会社に入ってからPostgreSQLを使い始めました。というわけで、初心者ですがPostgreSQL アドベントカレンダー 2011に参加してみます。

さて、PostgreSQL 9.1からSQL/MED規格の一部である 外部データラッパ (FDW:Foreign Data Wrapper) がサポートされました。すでに PostgreSQL アドベントカレンダー 12月3日分にて、板垣さんが WebAPIをfdwから叩いてます。この記事では www_fdw という既存のfdwを利用する方法でしたが、今回は実際に自分でfdwを作ってみます。

fdwはAPIを6個程度書くだけで良いのでそれだけでもかなり書きやすいのですが、いかんせんCで書く必要があります。そこで、 multicorn を使ってpythonでfdwを書いてみました。

なにを題材に書こうかなと思ったのですが、Pure Pythonで作られた全文検索エンジンWhoosh を使ってみました。

ソースコードは、こちら に置いてあります。

準備

まず、以下の二つをインストールする必要があります。

  • whoosh
  • multicorn

下にubuntuで叩いたコマンドを書いておきます。

  % sudo atp-get install postgresql-9.1  # postgresql-9.1を入れる
  % sudo apt-get install python-dev  # multicornのcompileにヘッダが必要
  % sudo apt-get install python-pip  # pythonのパッケージ管理ツールpipを入れる

  % sudo pip install pgxnclient  # pgxnを扱うためのクライアント
  % sudo pip install whoosh  # 全文検索エンジン
  % sudo pip install -e "hg+http://bitbucket.org/r_rudi/whooshfdw#egg=whooshfdw"  # 今回実装したパッケージをbitbucketからインストールする

  % sudo pgxn install multicorn --testing  # multicornを入れる

なお、今回はPostgreSQLサーバがpythonを叩くため、パッケージはvirtualenv環境ではなく、システム自体にインストールしてください。

whoosh index作成

全文検索するためにはまずインデックスを作成する必要があります。

registerというクラスを用意しておきましたのでそれを使います。

今回は、wikipediaの全ページのタイトルだけが含まれたファイルを検索してみます。

http://dumps.wikimedia.org/jawiki/20111203/ から jawiki-20111203-all-titles-in-ns0.gz をダウンロードし、/tmpに展開しておいてください。

from whooshfdw import register

register.register(file='/tmp/jawiki-20111203-all-titles-in-ns0', indexdir='/tmp/indexdir')

手元のマシンではだいたい40分ほどかかりました。お試しの場合はhead -n 1000とかしてください。

なお、インデックスですが決め打ちで2-gramで作成してあります。このあたりはコードを読んでくださいね。

SQL

準備が整ったところでいよいよfdwです。まずは Server と Tableを作成します。

CREATE EXTENSION multicorn;  -- multicornをDBにいれる
CREATE SERVER whoosh_srv FOREIGN DATA WRAPPER multicorn options (
        wrapper 'whooshfdw.whooshfdw.WhooshFDW' -- Server作成
);
CREATE FOREIGN TABLE whooshtable( -- FOREIGN TABLE作成
        id numeric,
        title character varying
) server whoosh_srv options (
        indexdir '/tmp/indexdir'  -- インデックスの場所をオプションで指定
);

できたところで SELECT 実行です。

% psql -c "SELECT * from whooshtable where title LIKE '%どこでも%';"
 id |       title        
----+--------------------
  1 | どこでもまど
  2 | どこでもドア
  3 | どこでもパス
  4 | どこでも大砲
  5 | どこでもCHU
  6 | どこでもドアー
  7 | どこでもいっしょ
  8 | どこでもチョコボ
  9 | どこでもWiiの間
 10 | どこでもドラえもん
(10 rows)

ちゃんと返ってきてますね。

実装の解説

multicornを使ったfdwの実装は ForeignDataWrapper クラスを継承したクラスを作成し、コンストラクタである __init__ と実行メソッドである execute を実装するだけです。

__init__ではsuperを呼び出すだけです。また、実際の検索を行うexecuteの中では yield を使って値を次々に返して行くだけです。

下はfdwの機能に絞ったコードの抜粋です。(全部はbitbucketを見てください)

class WhooshFDW(ForeignDataWrapper):
    def __init__(self, options, columns):
        super(WhooshFDW, self).__init__(options, columns)
        self.columns = columns
        self.indexdir = options["indexdir"]  # CREATE TABLE で指定したオプションを持ってくる

    def execute(self, quals, columns):
        for query in quals:  # qualsはWHERE句の中身が入っている
            q = parser.parse(query.value)
            with ix.searcher() as searcher:
                count = 1
                for r in searcher.search(q):
                    res = {'id': count, 'title': r["title"].encode('utf-8')}
                    yield res  # 値を辞書形式で返してあげる
                    count += 1

まとめると、

  • __ini__の中でsuperを呼ぶ
  • executeの中でyieldを使って値を次々に返せるようにする

これだけ。


注意点

なお、qualsというのはWHERE句の中身です。そしてwhere句は*必ず*適用されます。例えば、

def execute(self, quals, columns):
    for i in range(1,20):
        yield(i, "hoge")

としておいて、

SELECT * FROM whooshtable WHERE id = 10;

というSQLを実行した場合、「executeでqualはなにも使ってないんだから1から20まで表示されるだろう」と思いますよね。でもそうではなく、ここでは 10,hoge しか出てきません。

速度は?

実用を求めるならCで書けよな、と思いますが一応。

本体 Mac Mini (mid 2011)
OSUbuntu on Virtualbox
CPU2.4GHz(Core 2 Duo)
メモリ 8G
postgres 9.1

PostgreSQLの設定はubuntuのそのまんまです。っていうか、VirtualBoxという時点で評価の意味がないような気がしますが…。

1247130行のwikipediaのタイトルだけを抜き出したものでindexを作成するのに

  % time python register.py
  2571.88s user 289.96s system 91% cpu 51:54.10 total

2571秒はだいたい42分。これをfdw経由で検索すると、

 Foreign Scan on whooshtable  (cost=10.00..15.00 rows=9999999 width=64) (actual time=619.132..620.073 rows=10 loops=1)
   Filter: ((title)::text ~~ '%どこでも%'::text)
   Foreign multicorn: multicorn
   Foreign multicorn cost: 10
 Total runtime: 681.000 ms

でした。ちなみに普通にpythonで検索してみました。timeitを使って、100回実行して平均を出してみると、

  % python search.py
  15.917749 msec

おやまあ、やっぱりPostgreSQLからpythonを呼び出すコストが結構かかるようですね。pypyでも試してみたくなりますが止めておきます。


まとめ

今回は PostgreSQL 9.1から搭載されたfdwをPythonで実装できるmulticornを使って、pure pythonの全文検索エンジンwhooshをSQLから叩けるようにしてみました。

…字で書くとなんかむちゃくちゃですね。でも、やったことは非常に少しなのでPostgreSQLの拡張性すごい!ということで。

明日は DaiMotoh さん、お願いします。

2011-12-04

pysetup3のご紹介

python2ではsetuptoolsやdistutilsがありますが、python3では ”packaging”という新しいパッケージ用ライブラリが搭載されます。

pysetup3はこのpackagingを使うためのコマンドです。これは、setuptoolsやdistutilsを使うためのコマンドがpipやeasy_installである、という関係と同じです。

まとめるとこういう関係になります。(正確にはちょっとずれていますがまあこんなものかと)

ライブラリツール
python3.2までdistutils/setuptools/distributeeasy_install/pip/buildout
python3.3〜packagingpysetup3

なお、packagingはpython2.4〜3.2ではdistutils2という名前でバックポートされ、サードパーティパッケージとして配布されます。

pysetup3のドキュメントはこちらです。

http://docs.python.org/dev/install/pysetup.html

使い方

pysetup3はpython3.3から標準搭載されます。python 3.3はまだリリースされていないので、使うには http://hg.python.org/cpython/ から開発版を取得してくる必要があります。あるいは、python2〜3.2で使うにはhttps://bitbucket.org/tarek/distutils2/wiki/Home からソースをとってくる必要があります。なお、distutils2の場合、listコマンドが使えないなどの制限がありますのでご注意ください。

さて、pysetup3の使い方です。まずはhelpを見ます。

  % pysetup3 --help
  Usage: pysetup [options] action [action_options]

Actions:
    run: Run one or several commands
    metadata: Display the metadata of a project
    install: Install a project
    remove: Remove a project
    search: Search for a project in the indexes
    list: List installed projects
    graph: Display a graph
    create: Create a project
    generate-setup: Generate a backward-compatible setup.py

ちなみに、distutils2ではこうなります。

  Actions:
    run: Run one or several commands
    metadata: Display the metadata of a project
    install: Install a project
    remove: Remove a project
    search: Search for a project
    graph: Display a graph
    create: Create a Project

listがないのはどういうことだって言う感じですが…

検索 (search)

ということで、まずはbuchoパッケージを検索してみます。

  % pysetup3 search bucho
  not implemented
  %

...


えーっと。実装されてないって…

気を取り直して次行きましょう。

インストール (install)

落としてきたtar.gzを使って install してみます。

  % pysetup3 install bucho-0.1.1.tar.gz
  Installing from archive: '/home/prosou/shirou/bucho-0.1.1.tar.gz'
  Traceback (most recent call last):
    File "setup.py", line 2, in <module>
      import setuptools
  ImportError: No module named 'setuptools'
  failed to install

あー、buchoはsetuptoolsに依存しているのですね。pysetup3 install distribute をしたらこのエラーは出なくなりましたが、代わりに

  option --single-version-externally-managed not recognized

と言われてしまいました。よく分かりません…

pysetup3の作者、tarekのパッケージなら平気だと思います。

  % pysetup3.3 install flake8-1.0.tar.gz
    .....

  % pysetup3.3 list
   'flake8' 1.0 (from '/home/rudi/local/lib/python3.3/site-packages/flake8-1.0-py3.3.dist-info')
  Found 1 projects installed.

うまくインストールできたようです。

なお、インストールは

  • pypi
    • 検索はできなくてもインストールはできます。 pysetup3 install flake8としてください
  • tar.gzへのURL (http://host/packages/project-1.0.tar.gz)
  • setup.pyかsetup.cfgが含まれたディレクトリ

からもインストールできます。また、

  % pysetup3 install project==1.0

というようにすることで、インストールするバージョンを決めることもできます。

インストール済みのパッケージリスト (list)

listで今インストールされているパッケージのリストが出ます。

  % pysetup3.3 list
   'flake8' 1.0 (from '/home/rudi/local/lib/python3.3/site-packages/flake8-1.0-py3.3.dist-info')
  Found 1 projects installed.

情報の表示 (metadata)

パッケージの情報を得るにはmetadataを使います。

  % pysetup3.3 metadata flake8
  Metadata-Version:
      1.1
  Name:
      flake8
  Version:
      1.0
  Platform:
      UNKNOWN
  Supported-Platform:
  Summary:
      code checking using pep8 and pyflakes
  Description:
      ======  
  (以下省略)

また、-fをつけることにより、表示される情報を制限することも出来ます。

  % pysetup3 metadata -f name -f version flake8
  Name:
      flake8
  Version:
      1.0

インストールされているものにしか使えないようです。

グラフの表示 (graph)

  % pysetup3.3 graph flake8
  'flake8' 1.0

依存するパッケージのグラフを表示してくれるそうです。

アンインストール (remove)

  % pysetup3.3 remove flake8
  'flake8' cannot be removed.
  Error: [Errno 18] Cross-device link

what? …ちょっと今回は追いませんが、これがきちんと出来るのがいいところなのに…


プロジェクトを作成する (create)

createコマンドを打つと、setup.cfgを対話型で作ってくれます。途中でyを答えると今のディレクトリをチェックして全部含めてくれますので便利です。

ちなみに、pysetupはsetup.pyではなく、setup.cfgを使うようになることに注意してください。 (このあたりはpycon 2011 JPのtarekの講演を参考にしてください。)

  % pysetup3.3 create
  Project name [setup]: test
  Current version number [1.0.0]: 
  Project description summary: 
     > Thi is test
  Author name: shirou
  Author email address: rudy@example.com
  Project home page: test
  Do you want me to automatically build the file list with everything I
  can find in the current directory? If you say no, you will have to
  define them manually. (y/n): y
  Do you want to set Trove classifiers? (y/n): y
  Please select the project status:
  0 - Planning
  1 - Pre-Alpha
  2 - Alpha
  3 - Beta
  4 - Production/Stable
  5 - Mature
  6 - Inactive
  
  Status: 1
  What license do you use?: BSD
  Matching licenses:
  
     1) License :: OSI Approved :: BSD License
  
  Type the number of the license you wish to use or ? to try again:: 1
  What license do you use?:
  Do you want to set other trove identifiers? (y/n) [n]: n
  Wrote "setup.cfg".

また、setup.pyがあると

  % pysetup3 create
  A legacy setup.py has been found.
  Would you like to convert it to a setup.cfg? (y/n)
   [y]: y

と聞いてくれます。でもsphinxを試したら ImportError: No module named 'sphinx' と言われてしまいました。

互換性のためにsetup.pyを作る (genearte-setup)

  % generate-setup
  The setup.py was generated

とすると、setup.pyが出来上がります。でも、現段階では別にディレクトリの内容を読んでくれるわけではなく、単にsetup.pyのひな形ができるだけです。

コマンド (run)

pysetup3には今まで述べてきたコマンドの他にも setup.py 相当コマンドがあります。 setup.pyが使われなくなる代わりに、今までsetup.pyで行ってきたことがここに入っているという感じですね。

  % pysetup3 run --list-commands

  List of available commands:
    bdist: create a built (binary) distribution
    bdist_dumb: create a "dumb" built distribution
    bdist_wininst: create an executable installer for Windows
    build: build everything needed to install
    build_clib: build C/C++ libraries used by extension modules
    build_ext: build C/C++ extension modules (compile/link to build
    directory)
    build_py: build pure Python modules (copy to build directory)
    build_scripts: build scripts (copy and fix up shebang line)
    check: check PEP compliance of metadata
    clean: clean up temporary files from 'build' command
    install_data: install platform-independent data files
    install_dist: install everything from build directory
    install_distinfo: create a .dist-info directory for the distribution
    install_headers: install C/C++ header files
    install_lib: install all modules (extensions and pure Python)
    install_scripts: install scripts (Python or otherwise)
    register: register a release with PyPI
    sdist: create a source distribution (tarball, zip file, etc.)
    test: run the project's test suite
    upload: upload distribution to PyPI
    upload_docs: upload HTML documentation to PyPI

まとめ

というわけで、python3.3から使えるようになるpysetupコマンドについて述べてきました。正直まだ使えないなというレベルではありますが、3.3リリースが予定されているのは来年8月ですし、これからどんどん良くなっていくと思います。

明日は初心者向けのエントリを書いてくださる @takanory さんにお願いします。