iakioの日記 RSSフィード

2010-12-09

psycopg2でhstoreをdictにマップ

| 02:40 | psycopg2でhstoreをdictにマップ  - iakioの日記 を含むブックマーク はてなブックマーク - psycopg2でhstoreをdictにマップ  - iakioの日記

hstoreというのはcontribにはいっているkey-valueデータ型です。

psycopg2の2.3.0以降では、hstoreをPythonのdictにマップできるそうです。

ところでhstoreの前にARRAYはどうなってるのと思ったらサポート済みの様子。

>>> import psycopg2
>>> conn = psycopg2.connect("")
>>> cur = conn.cursor()
>>> cur.execute("select %s", ([1,2,3],))
>>> cur.fetchone()
([1, 2, 3],)

cursor.mogrify()で実際に発行されるクエリを確認できます。

>>> cur.mogrify("select %s", ([1,2,3],))
'select ARRAY[1, 2, 3]'

タプルをROWにはできるけどその逆はできないのかもしれない。

>>> cur.mogrify("select %s", ((1,"foo"),))
"select (1, E'foo')"
>>> cur.execute("select %s", ((1,"foo"),))
>>> cur.fetchone()
('(1,foo)',)

さて、hstoreを使うには、DBにhstoreをインストールした上で、psycopg2.extras.register_hstore()を実行します。これを実行した時にhstoreのoidを取りにいっている様子。

>>> import psycopg2.extras
>>> psycopg2.extras.register_hstore(cur)
>>> cur.execute("select 'a => 1'::hstore")
>>> cur.fetchone()
({'a': '1'},)
>>> cur.mogrify("select %s", (dict(a=1, b=2),))
"select hstore(ARRAY[E'a', E'b'], ARRAY[1, 2])"
>>> cur.execute("select * from each(%s)", (dict(a="foo", b="bar"),))
>>> cur.fetchall()
[('a', 'foo'), ('b', 'bar')]

あとEventletを使ったLISTEN/NOTIFYのサンプルもありましたが理解してないのでリンクだけ貼っておきます。

SatchellSatchell2012/10/07 11:43A piece of erudition unlkie any other!

hqltnqhqltnq2012/10/09 01:44l1JhT4 , [url=http://fxtkvscdjach.com/]fxtkvscdjach[/url], [link=http://fmkeldzbcnhz.com/]fmkeldzbcnhz[/link], http://hatalerarkos.com/

xioloyyhuxoxioloyyhuxo2012/10/09 15:49X2AAyM <a href="http://qjfyudsoiako.com/">qjfyudsoiako</a>

orqpkjzcorqpkjzc2012/10/10 03:08HcF4OM , [url=http://cvliwaymqpqy.com/]cvliwaymqpqy[/url], [link=http://ekbbiztsxejn.com/]ekbbiztsxejn[/link], http://dmessezkctll.com/

zufnukwvlfzufnukwvlf2013/07/26 22:33brmopqptuhsftrm, <a href="http://www.nlucmtnhwn.com/">blkktychie</a> , [url=http://www.dvxkbncuwx.com/]wepicvclff[/url], http://www.btzqexytgf.com/ blkktychie

qcsblxqlspqcsblxqlsp2013/07/30 07:39hpgukqptuhsftrm, <a href="http://www.qzwpvlcfex.com/">ywuaildqlq</a> , [url=http://www.mrcdtxfwcd.com/]vozneoomct[/url], http://www.evkykswgvk.com/ ywuaildqlq

oogzsdzqgioogzsdzqgi2013/11/24 03:40eprnoqptuhsftrm, <a href="http://www.muykjdlpyj.com/">wfjbpinqzp</a> , [url=http://www.tocxuezory.com/]wguvglwpvd[/url], http://www.ecbpvstmbl.com/ wfjbpinqzp

ychwgqkgfcychwgqkgfc2014/03/19 23:20anmeiqptuhsftrm, <a href="http://www.fxkwmddkmc.com/">rtgdbrqqic</a> , [url=http://www.zboyralwnn.com/]gjafdryuig[/url], http://www.pcpxifkqhj.com/ rtgdbrqqic

トラックバック - http://postgresql.g.hatena.ne.jp/iakio/20101209

2008-07-05

psycopg2とバージョン

| 17:59 | psycopg2とバージョン - iakioの日記 を含むブックマーク はてなブックマーク - psycopg2とバージョン - iakioの日記

何となくDjangoでもやってみようかと思ったらいきなりハマりました。

  File "C:\Python25\Lib\site-packages\django\db\backends\postgresql_psycopg2\base.py", line 57, in cursor
    postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
ValueError: invalid literal for int() with base 10: '3,'

ん?'3,'??

testdb=# select version();
                       version
-----------------------------------------------------
 PostgreSQL 8.3.3, compiled by Visual C++ build 1400
(1 row)

何でしょうかそのコンマは。

何やらWindowsの8.3以降ではversion()の最後にコンマが付くらしいです。若干腹も立ちますが本来バージョン番号が欲しければPQserverVersionかPQparameterStatusを使うべきで、psycopg2にはそれが実装されていない。ruby-pgだとこんな感じ。

irb(main):005:0> c = PGconn.open("dbname=db1")
=> #<PGconn:0x805f5e8>
irb(main):008:0> c.parameter_status("server_version")
=> "8.3.3"
irb(main):009:0> c.server_version
=> 80303

惜しいなぁ。psycopg2はわりと良くできてると思ってたのに。

トラックバック - http://postgresql.g.hatena.ne.jp/iakio/20080705

2008-05-13

SkyToolsについて調べる(2) - ログの出力

| 07:27 | SkyToolsについて調べる(2) - ログの出力 - iakioの日記 を含むブックマーク はてなブックマーク - SkyToolsについて調べる(2) - ログの出力 - iakioの日記

そういえば書き忘れてましたが私はskytools-2.1.5のコードを見ながらこれを書いてました。と思ったら2.1.6がリリースされているのに気付いてませんでした。というわけで今回から2.1.6を見ながら書きます。あとOSFreeBSD 6.3 Releaseです。

skytools-2.1.6はFreeBSDでgmake installするとエラーになるので、Makefile内の"make"を"$(MAKE)"に書き換えておきましょう。このバグは修正済のようです*1

--- Makefile.orig       2008-04-05 22:24:51.000000000 +0900
+++ Makefile    2008-05-12 22:26:57.000000000 +0900
@@ -38,7 +38,7 @@

 python-install: config.mak modules-all
        $(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR)/
-       make -C doc DESTDIR=$(DESTDIR) install
+       $(MAKE) -C doc DESTDIR=$(DESTDIR) install

 python-install python-all: python/skytools/installer_config.py
 python/skytools/installer_config.py: python/skytools/installer_config.py.in config.mak
@@ -78,7 +78,7 @@
        debuild -uc -us -b

 tgz: config.mak clean
-       make -C doc man
+       $(MAKE) -C doc man
        $(PYTHON) setup.py sdist -t source.cfg -m source.list

 debclean: distclean

今回はskytools.DBScriptからのログの出力について調べてみますが、基本的にはPythonのloggingモジュールそのまんまです。

ログを出力する方法

self.logがLoggerオブジェクトなので、self.log.info()とかself.log.error()とかでログを出力できます。前のプログラムをちょっとマトモにしてみると、

import sys
import skytools

class Hello(skytools.DBScript):
    def __init__(self, args):
        skytools.DBScript.__init__(self, 'hello', args)

    def work(self):
        db = self.get_database("db", autocommit=1)
        cx = db.cursor()
        cx.execute("select 'hello' as msg")
        res = cx.dictfetchone()
        self.log.info("message is %(msg)s", res)

if __name__ == "__main__":
    script = Hello(sys.argv[1:])
    script.start()

"%(msg)s"って何って方は

404 Not Found

あたりを見てください。別にself.log.info("message is %s", res['msg'])でもいいんだけど。

実行結果

2008-05-12 22:13:41,268 75177 INFO message is hello
2008-05-12 22:13:42,270 75177 INFO message is hello
2008-05-12 22:13:43,272 75177 INFO message is hello
...

起動時の引数で--verboseが指定されていれば、DEBUG以上のログが出力され、--quietであればWARNNING以上のログのみが出力されます。どちらも指定されていなければ、INFO以上のログのみが出力されます。

ログをファイルに出力する

先程の例ではログをstderrに出力していました(logging.handlers.StreamHandlerが使われていた)。

ログをファイルに出力する場合は、設定ファイルでlog_fileを指定します(logging.handlers.RotatingFileHandlerが使われます)。またログのローテーションをlog_size、log_countで設定します。

skylogを使う

もっと色んなログの設定をしたい場合は、設定ファイルでuse_skylog=1としてskylogを使います。skylogを使うと、Pythonの他のLoggingHandler(例えばsyslogを使ったりログをメールで送ったり)を使うことや、ログのフォーマットを詳細に指定することができます。

skylogは、設定ファイルをカレントディレクトリのskylog.ini、~/.skylog.ini、/etc/skylog.iniの順で探し、最初に見つけたファイルを読み込みます。

設定ファイルはPythonのlogging.config.fileConfig()そのものなので、そっちを見てねという感じなのです

skylogの独自のHandlerとして

  • EasyRotatingFileHandler(ほとんどRotatingFileHandlerと一緒だけどパスの指定に"~"を使うことができる)
  • UdpLogServerHandler(JSON形式でUDPで送信する。何に使うんだ?)
  • LogDBHandler(ログをDBに保存する。けどlog.add()という関数は自分で作らなきゃいけないのだろうか)

というハンドラクラスを使うことができるみたいです。

あとソースツリーのpython/conf/skylog.iniに設定ファイルのサンプルがあります。駆け足になりましたが力尽きたのでこの辺で。

*1:06/03追記:修正されたバージョン2.1.7がリリースされました

LarkLark2012/01/12 03:40Percfet shot! Thanks for your post!

vyrugouvyrugou2012/01/12 18:07WqdaHu <a href="http://bikcuisoadpz.com/">bikcuisoadpz</a>

mgkcabbquvxmgkcabbquvx2012/01/13 23:30ET5tQD , [url=http://oisjuydxiaem.com/]oisjuydxiaem[/url], [link=http://okvxreacafxh.com/]okvxreacafxh[/link], http://yggbtzibtmma.com/

htoxjqbvmzhtoxjqbvmz2012/01/14 20:56Olo51I <a href="http://wiqeutrwdgcf.com/">wiqeutrwdgcf</a>

tcreketcreke2012/01/16 20:33QVaXyc , [url=http://mbbmjjjnoxlu.com/]mbbmjjjnoxlu[/url], [link=http://mnpppqwdumdl.com/]mnpppqwdumdl[/link], http://jdoqylxyapyb.com/

トラックバック - http://postgresql.g.hatena.ne.jp/iakio/20080513

2008-05-09

SkyToolsについて調べる(1) - skytools.DBScript

| 08:16 | SkyToolsについて調べる(1) - skytools.DBScript - iakioの日記 を含むブックマーク はてなブックマーク - SkyToolsについて調べる(1) - skytools.DBScript - iakioの日記

SkyToolsって?

SkyToolsは、skypeが作ったPostgreSQLのクラスタリング用のツール群です。ほとんどがPythonで書かれています(あとはPL/pgSQLとC)。Python + PostgreSQLな人はやってみればいいと思うよ。

SkyToolsの代表的なツールはLondiste、PgQ、WalMgrとかいうのがあります。

ちなみにPgQあたりについては調べている方がいらっしゃっいました。

まだブロ: [PostgreSQL] Skytools

まだブロ: [PostgreSQL] PgQ

skytools.DBScriptって?

で、今回はskytools.DBScriptのあたりを見てみます。

skytools.DBScriptを使うと、データベースに接続して定期的に何かを実行するようなスクリプトを簡単に書くことができます。先述のLondisteとかPgQもこのskytools.DBScriptを使って実装されています。以下は1秒毎に"select 'hello'"を実行するスクリプトです。

import sys
import skytools

class Hello(skytools.DBScript):
    def __init__(self, args):
        skytools.DBScript.__init__(self, 'hello', args)

    def work(self):
        db = self.get_database("db", autocommit=1)
        cx = db.cursor()
        cx.execute("select 'hello'")
        res = cx.dictfetchone()
        print res

if __name__ == "__main__":
    script = Hello(sys.argv[1:])
    script.start()

ポイントはskytools.DBScriptを継承して、定期的に実行したい処理をworkメソッドの中に書くことぐらいです。あとコンストラクタの中でskytools.DBScript.__init__を呼んでますが、この時の第二引数がservice_nameというものらしく、設定ファイルのセクション名(後述)に使ったり、ログに出力されたりします。

cx.dictfetchone()というのはDBAPIに対する拡張です。だいたい想像通りの動きをします。

設定ファイルを書く

で、実行する時は第一引数に設定ファイルを指定します。最も簡単な設定ファイルはこんな感じ。

[hello]
db = dbname=db1
pidfile = /tmp/hello.pid

先程も言った通り、設定ファイルではservice_nameをセクション名として指定します。接続先データベースを指定するキー名は任意で(ここではdbとなっていますが)、プログラム内でself.get_databaseの引数で指定する名前そのものになっています。

その他、以下の設定が可能であるということが観測されていますw

  • loop_delay(既定値:1.0) 繰り返しworkを実行する間隔の秒数です。
  • connection_lifetime(既定値:20*60) データベースへの接続を維持する秒数です。デフォルトでは20分に一度接続しなおします。
  • use_skylog(既定値:0) skytools.skylogを使うかどうか。たぶんPythonのloggingモジュールを使った何か。そのうち調べます。
  • logfile(既定値:"") use_skylogが0の場合、ログの出力先です。
  • logsize(既定値:10*1024*1024) そういえばログについてここまで何も書いてませんが、self.log.error()とかで出力できます。
  • logcount(既定値:3)
  • job_name(既定値:service_name)

実行とコマンドライン引数

さてここまでくればめでたく実行できます。

$ python hello.py hello.ini
{'?column?': 'hello'}
{'?column?': 'hello'}
...

それだけではなく、他にもデフォルトでいくつかのコマンドライン引数を使うことができます。

$ python hello.py hello.ini --help
Usage: hello.py [options] INI

Options:
  -h, --help      show this help message and exit
  -q, --quiet     make program silent
  -v, --verbose   make program verbose
  -d, --daemon    go background

  control running process:
    -r, --reload  reload config (send SIGHUP)
    -s, --stop    stop program safely (send SIGINT)
    -k, --kill    kill program immidiately (send SIGTERM)

現段階ではquietとverboseは意味無いですが、それ以外はだいたい思ったとおりに動くと思います(説明てきとう)。力尽きてきたのでとりあえず今回はこんなもんで。

TODO:skylogについて調べる。

TODO:statisticsについても調べる。

AnnikaAnnika2012/10/09 13:29Kudos! What a neat way of thinknig about it.

irmrjhoiiirmrjhoii2012/10/10 01:13l57dtN <a href="http://nwmrlnsvvxlk.com/">nwmrlnsvvxlk</a>

rymihdawlfnrymihdawlfn2012/10/11 09:03sbTJnK , [url=http://znhjnjapyyih.com/]znhjnjapyyih[/url], [link=http://yxwdlslfehma.com/]yxwdlslfehma[/link], http://bliknkpdcqvq.com/

jprqqtjsjprqqtjs2012/10/12 00:54dWw7DI <a href="http://bkyrefjqpovp.com/">bkyrefjqpovp</a>

zlmdqfvqaazlmdqfvqaa2012/10/12 07:11rBecko , [url=http://nsuowkluuojk.com/]nsuowkluuojk[/url], [link=http://ewzvvynamrhe.com/]ewzvvynamrhe[/link], http://suzxbmxiwbcr.com/

トラックバック - http://postgresql.g.hatena.ne.jp/iakio/20080509