Psycopg2でサーバーに接続できない
Psycopg2を使っていて、multiprocessingでデータベースに接続してデータを入れる処理を書こうとしていたんだが、↓のエラーで躓いた。
could not connect to server: Connection refused Is the server running on host "localhost" and accepting TCP/IP connections on port 5432?
netstat -an| grep 5432
で確認しても
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN
とあって、動いてるように見える。
postgresql.confの設定も
listen_address = 'localhost' port = 5432
となっていることを確認した。
それでも繋がらない。
結論を言うと、
con = psycopg2.connect(database=db, user=user, password=passwd)
のように書く必要がある。修正前は
con = psycopg2.connect(database=db, host='localhost', user=user, password=passwd)
としていた。
hostを設定していたとき、ログやpsなどで見ていると5432以外のportでのアクセスがあった。きっとこれがダメなんだろうとあたりをつけて何とかTCP/IPではなくUnixドメインでアクセスできないかと探していると、psycopg2では、hostの設定を省くとUnixドメインでのアクセスになるというので試してみたらうまくつながった。
クラスの並列化
multiprocessingモジュールで関数を並列化する方法はネットにあるが、クラスを並列化するというのは少なかったので、やってみた。結論としては、処理速度上げるのしんどいしよくわからんエラー出るしで結局関数を並列化する事で落ち着いた。
環境
Ubuntu12.04
Python2.7
PostgreSQL9.1.6
実装
ここの、プロセスへメッセージを渡す のところを参考に実装してみた。
class Sample: def __init__(self, json): self.json = json self.con = DBに繋ぐ関数 self.cur = self.con.cursor() def __call__(self): #実際に並列化して実行したい関数 self.add_db() def creat_sql(self): hogehoge def add_db(self): #クラス変数やインスタンス変数の扱いが面倒なので、関数をネストさせてローカルスコープ内で処理 def main(): sql = self.creat_sql() self.cur.execute(sql) class Worker(multiprocessing.Process): def __init__(self, task_queue, result_queue): multiprocessing.Process.__init__(self) self.task_queue = task_queue self.result_queue = result_queue def run(self) while True: next_task = self.task_queue.get() if next_task == None: self.task_queue.task.done() break answer = next_task() self.task_queue.task_done() self.result_queue.put(answer) f = open('読み込むファイル', 'r') jsons = simplejson.load(f) tasks = multiprocessing.JoinableQueue() results = multiprocessing.Queue() workers = [Worker(tasks, results) for i in range(multiprocessing.cpu_count() * 10)] for w in workers: w.start() #各ワーカーにデータを挿入 for w, data in itertools.izip(itertools.cycle(workers), json): tasks.put(tweet.Tweet(data)) #各Worker に poison pill を挿入 for w in iter(json): tasks.put(None) tasks.join() jobs = len(json) while jobs: res = results.get() print 'res:', res jobs -= 1
Workerクラス以下はほとんど変えてないな。
取り敢えずはこれで動いたんだが、ここでも言ってるようにあまり処理速度が向上しなかった(8coreの自分の環境の場合、CPU使用率が20%程度にしかならなかった。map関数を使ったときは90%程度まで向上した)。ただ単にプログラムの書き方が悪いんだろう。
Workerクラスを使わずにmultiprocessing.Poolのmap関数を使ったほうがずっと早かった(Workerクラス使用時:2H → map関数使用時:11m)。これだけ違うってことは、プログラムの書き方が悪いんだろう。たぶん大事(だと思うから)二度書いてみた。
map関数使用時のコード
def add(data): s = Sample(data) s.add() p = multiprocessing.Pool() p.map(add, jsons)
詰まったところ備忘録
1.Sampleクラスのメソッドでcursorオブジェクトは渡せない(↓のような使い方)ので、curはインスタンス変数として持っておく
#ダメな例 cur = con.cursor() def hoge(self, a, b, cur): hogehoge cur.execute(sql) self.hoge(a=aaa, b=bbb, cur=cur) #良い例 self.cur = self.con.curosr() def hoge(self, a, b): hogehoge self.cur.execute(sql) self.hoge(a=aaa, b=bbb)
2.インスタンス変数
クラスメソッドAの中で定義したインスタンス変数AとクラスメソッドBの中で定義したインスタンス変数Aは別だと思っていたが、同じだった。
class Sample: def hoge(self): self.a = 'aaa' def fuga(self): self.a = 'bbb' self.hoge() # self.a = 'aaa'になる self.fuga() # self.a = 'bbb'に上書き
3.よくわからんエラー
"psql: FATAL: remaining connection slots are reserved for non-replication superuser connections”
解決できなかったorz
red hat4にnumpy, scipyインストール
前回はred hat4にyumを入れるだけで肝心のnumpyとscipyをインスト出来なかったので、再挑戦してみた。
前回numpyがインスト出来なかったときにでてきたエラーが、Connection Peerだったので、改めて実行するとすんなり葉行った。なのでここは特に記載なし。
次にnosetestをpipでいれて、scipyも入れるかーとコマンドを打つと
sudo pip install scipy Import Error: libimf.so: cannot open shared object file: No such file or directory
このlibimf.soって何なん?って思ってぐぐると、インテルのコンパイラ関係のライブラリなのかな?それでこのエラーの解決方法に従って.bashrcを書き換えて再度読み込んだが、変わらなかった。
さらに探していくと、このページを見つけ、従ってやってみたらうまく入ったので、コマンドを残しておく。
find /opt/intel -name libimf.so /opt/intel/cc/10.1/lib/libimf.so # for 32bit /opt/intel/cce/10.1/lib/libimf.so # for 64bit /opt/intel/fc/10.1/lib/libimf.so /opt/intel/fce/10.1/lib/libimf.so /opt/intel/cc/9.1/lib/libimf.so /opt/intel/cce/9.1/lib/libimf.so /opt/intel/fc/9.1/lib/libimf.so /opt/intel/fce/9.1/lib/libimf.so ... #red hatのバージョンが古いから取り敢えず古い方いれておこうということで、9.1を設定ファイルに書き込む sudo vim /etc/ld.so.conf /opt/intel/cce/9.1/lib ←追記 #ライブラリへのリンクを作成 sudo /sbin/ldconfig
として、再度実行すると
sudo pip install scipy Import Error: libifport.so.5: cannot open shared object file: No such file or directory #↑と同様のエラーのようなので、 find /opt/intel -name libifport.so.5 #で見つけたやつを設定ファイルに書き込む sudo vim /etc/ld.so.conf /opt/intel/fce/9.1/lib ←追記
これで再度実行すると、無事インストできました^^
追記
インテルCコンパイラを使用してソースからインストールする場合、9.1では動かず10.1を使う必要があった。/opt/intel/cce/10.1/bin/などにiccvars.shがあり、
source /opt/intel/10.1/bin/iccvars.sh
RHEL4にyumをインストール
そもそもOSはRed Hatだがyumがないらしい。とりあえずバージョンが何なのかを知らないことには…と思い、ここを参考に
cat /etc/*-release
を実行すると、
Red Hat Enterprise Linux WS release 4
どうやらRHEL 4らしい。
…関係ないが、RHEL 4のサポート(厳密には違うんだろうが…)が2012.2で切れてた。どーすんだろ?
さて、せっかくならyum欲しいよね?ってことでインストールしてみた。
yumの公式サイト?を眺めて、取り敢えず2.9ならいいかな?ってことでこれをダウンロード、インストール
wget http://yum.baseurl.org/download/2.9/yum-2.9.8-1.src.rpm sudo rpm -ivh yum-2.9.8-1.src.rpm sudo rpmbuild --ba /usr/src/redhat/SPECS/yum.spec
ここまで実行したところで、
RPM build error: Fie not found by glob:/var/tmp/yum-2.9.8root/usr/lib/python?.?/site-packages/yum Fie not found by glob:/var/tmp/yum-2.9.8root/usr/lib/python?.?/site-packages/rpmUtils
というエラーが…少しぐぐったが分からずorz
別バージョンで試してみるか、ということで2.4.3をダウンロードして試したが同じエラー…
File not foundということでもしかしたら…と思い確認してみると、ファイルのパスが違ってた!
そしてふとsrc.rpmは hoge.spec という設定ファイルが云々とか見たのを思い出し、yum.specを開いてみると、ありましたよ
%{_bindir}/yum-arch /usr/lib/python?.?/site-packages/yum
これを↓のように書きなおして(localを追加)
%{_bindir}/yum-arch /usr/local/lib/python?.?/site-packages/yum
再度実行すると、python-elementtree, python-sqlite, urlgrabberがないようだ。どうやら依存関係が解消されない模様。
wget http://vault.centos.org/4.5/os/x86_64/CentOS/PRMS/python-{elementtree-1.2.6-5.el4.centos.x86_64,sqlite-1.1.7-1.2.1.x86_64,urlgrabber-2.9.8-2.noarch}.rpm sudo rpm -Uvh *.rpm
でダウンロードしてインストール。python-sqliteについてはsqlite3が入ってなかったのでまた依存関係で躓いた…
wget http://vault.centos.org/4.5/os/x86_64/CentOS/PRMS/sqlite-3.3.6-2.x86_64.rpm sudo rmp -Uvh sqlite-3.3.6-2.x86_64.rpm
でダウンロードしてインストール。依存関係を解消したところで再度python-sqliteをいれて、
sudo rpmbuild --ba /usr/src/redhat/SPECS/yum.spec
を試してみると Wrote: hogehoge
とか出てきたのでうまく入ったようだ。
sudo rpm -ivh /usr/src/redhat/RPMS/noarch/yum-2.4.3-1.rpm
で、whereis yumでパスが通ってることを確認して無事インスト成功!やったね(∩´∀`)∩ワーイ
さて、それではscipyいれますか!と思った矢先にまた問題発生…
There was a problem importing one of the Python modules required to run yum. The error leading to this problem was: No module named yum ... It's possible that the above module doesn't match the current version of Python, which is: 2.3.4
yumってモジュールが見つからないとか…
同じようなエラーに遭遇して解決した方がいらっしゃったので、その方のブログを参考にやってみた。
実際にパスが通ってるpythonは2.7だったので、
sudo ln -s /usr/local/lib/python2.7/site-packages/yum /usr/local/lib/python2.3/site-packages/
これを実行して試すとまた同様のエラーが…取り敢えずエラーとして出てきたrpmUtilsとrepomdもリンクを貼って再度scipyをインストールしようとすると、
Setting up repositories No Repositories Available to Set Up Reading repository metadata in from local files
と出た!やっとエラーから解放されたようだ
さて、scipyのインストールはeasy_installが楽だったかな?…と思いきや、
sudo yum list python-setuptools Setting up repositoies No Repositories Available to Set Up Reading repository metadata in from local files
…設定が必要なのね( ・´ω・`)
ってことで、JAISTをリポジトリに設定してみた。
wget http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/RPM-GPG-KEY-EPEL-4 sudo rpm --import RPM-GPG-KEY-EPEL-4 sudo vi /etc/yum.repos.d/epel.repo [epel] name = Fedora epel repository at Jaist baseurl = http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/4WS/$basearch/ gpgcheck = 1 enabled = 1
python-mecabで文字列をパースしてみる
環境はPython2.7, mecab0.98
def extract_keyword(string, word_class=['名詞']): tagger = MeCab.Tagger('mecabrc') nodes = tagger.parse(u'テスト文字列です')
のように文字列をパースしようとすると、下記のエラーが出た。
Traceback (most recent call last): File "hoge.py", line 35, in <module> extract_keyword(text) File "hoge.py", line 16, in extract_keyword nodes = tagger.parse(u'テスト文字列です #JAISTFES') File "/usr/lib/python2.7/dist-packages/MeCab.py", line 220, in parse def parse(self, *args): return _MeCab.Tagger_parse(self, *args) TypeError: in method 'Tagger_parse', argument 2 of type 'char const *'
ちなみに、tagger.parseでもtaggaer.parseToNodeでも同様。
ユニコード文字を渡すとこのエラーが出るらしい。
バイト文字列だとうまくパースできた^^
行列の和をとってみる
こんな感じの行列があって、すべてのキーワードの出現回数の合計を出したい。
paragraph_id | keyword1 | keyword2 | keyword3 | keyword4 |
---|---|---|---|---|
0 | 5 | 3 | 1 | 4 |
1 | 2 | 4 | 4 | 4 |
2 | 3 | 2 | 5 | 3 |
計算したい要素のみのリストを作っておく
matrix = [ [5,3,1,4], [2,3,3,3], [3,2,5,3] ]
すぐ思いつくのはforで回す方法だけど、sum関数とmap関数とリスト内包表記で実現してみた。
sum([sum(map(int,row)) for row in matrix])
ファイルから読み込むときに、文字列で解釈される場合は↑のようにint関数でキャストする。
初めから整数のリストを持ってる時は、↓の方法でいけると思う。
sum([sum(row) for row in matrix])
まず内側のmap(int,row) (rowはmatrixの要素)で、rowの要素を整数型に変換し、整数の要素を持つリストを作成する。
sum(map(int,row)) は作成されたリストの要素の合計を算出する。
[sum(map(int,row)) for row in matrix] でmatrixのすべての要素で、要素の要素の合計を要素として持つリストを作成する(分かりづらい表現やな)
最後に、↑で作成したリストの要素の和を算出する。