新年、明けましたらおめでとうございます。
2005年は、大変お世話になり、
お蔭様で、私としては大きな一歩を踏み出す事ができました。
2006年は、次の展開を自ら作り出せるかどうかの正念場と心得ております。
よろしくご指導ご鞭撻下さいますよう、心よりお願い申し上げます。
[謹賀新年2006_犬.html]
新年の挨拶
[ このエントリへはツッコミ出来ません ]
PostgreSQL で RDB 設計 その2
「PostgreSQL で RDB 設計 その1」の補足。
PostgreSQL では、WHERE 句に、正規表現が使えるので、いつも重宝している。
こんな感じ。
ANY(some_array) をカマせば、これができるだろうと期待していた。
いろいろ試したが、どうも無理っぽい[マニュアルより ANY/SOME(array)]。
そういう目的では、
配列型ではなく TEXT 型とかに配列表現を突っ込むのが良いだろう。
とりあえず TEXT 型で用意しておいて、記法は充分検討してゆっくり決めれば良い。
例えば、PHP の serialize(); の場合、数値配列は、
このキーと値との選り分けを正規表現なんかでやってられない。
そうなると独自記法がベストな気がしてきた( JSON とか XML とかも無意味に面倒)。
正規表現のメタキャラクタとして解釈されなくて、
尚且つ、データに使われなさそうな文字列を、セパレータにすれば良い。
クォーテーションの扱いにも注意。
以下、例:
PostgreSQL では、WHERE 句に、正規表現が使えるので、いつも重宝している。
こんな感じ。
- 使用前:
select * from some_table where some_field = 1 or some_field = 4 or ... ;
- 使用後:
select * from some_table where some_field ~ '^(1|4|...)$';
ANY(some_array) をカマせば、これができるだろうと期待していた。
いろいろ試したが、どうも無理っぽい[マニュアルより ANY/SOME(array)]。
そういう目的では、
配列型ではなく TEXT 型とかに配列表現を突っ込むのが良いだろう。
とりあえず TEXT 型で用意しておいて、記法は充分検討してゆっくり決めれば良い。
例えば、PHP の serialize(); の場合、数値配列は、
a:2:{i:0;i:123;i:1;i:456;}という感じで、キーと値とが交互に表れるが、
このキーと値との選り分けを正規表現なんかでやってられない。
そうなると独自記法がベストな気がしてきた( JSON とか XML とかも無意味に面倒)。
正規表現のメタキャラクタとして解釈されなくて、
尚且つ、データに使われなさそうな文字列を、セパレータにすれば良い。
クォーテーションの扱いにも注意。
以下、例:
create table fruit ( fruit_id serial, name text ); create table member ( member_id serial, name text, gender text, fruit text ); insert into fruit(name) values('りんご'); insert into fruit(name) values('みかん'); insert into fruit(name) values('いちご'); insert into fruit(fruit_id,name) values(12,'いちじく'); insert into member(name,gender,fruit) values('太郎','男',':::::1:::::3:::::'); insert into member(name,gender,fruit) values('花子','女',':::::2:::::3:::::'); insert into member(name,gender,fruit) values('次郎','男',':::::12:::::'); select * from member,fruit where member.fruit ~ (select ':{5}'||fruit.fruit_id||':{5}') order by member_id; member_id | name | gender | fruit | fruit_id | name -----------+------+--------+-------------------+----------+---------- 1 | 太郎 | 男 | :::::1:::::3::::: | 1 | りんご 1 | 太郎 | 男 | :::::1:::::3::::: | 3 | いちご 2 | 花子 | 女 | :::::2:::::3::::: | 2 | みかん 2 | 花子 | 女 | :::::2:::::3::::: | 3 | いちご 3 | 次郎 | 男 | :::::12::::: | 12 | いちじく (5 rows) Time: 1.069 ms select * from member where fruit ~ ':{5}(2|3):{5}' order by member_id; member_id | name | gender | fruit -----------+------+--------+------------------- 1 | 太郎 | 男 | :::::1:::::3::::: 2 | 花子 | 女 | :::::2:::::3::::: (2 rows) Time: 0.557 ms
ツッコミ
- 1: jrgrpmhu (07/25 23:48) jrgrpmhu
- <a href="http://jkdrbkij.com">jqgojfus</a> [URL=http://kuussydq.com]iquwdonv[/URL] qchjdqux http://uqxzqlta.com jgnoijpy mzibspho
PostgreSQL で RDB 設計 その1
4 年くらい前から PostgreSQL を使っている。
MySQL は、システム上必要な場合以外は使っていない。
MySQL が嫌いなわけではなく、
「何かみんな MySQL だなぁ…俺も MySQLer になろうかなぁ。」
と思ったことは数知れず。
でも、PostgreSQL にしかない機能の恩恵に、度々、与ってしまっているので、「乗り換え」には至らず。
それにしても、いろいろな RDBMS があるものだ ( RDBMS比較資料[PDFです] )。
各 RDBMS の特徴は、DB の設計や、チューニングの際に、顕著になるのではないだろうか?
「管理しやすくて、検索が速くて、更新もサクサクできる」
そんな DB はどうしたら実現できるだろうか…と考えていくと、自然と実装の話になっていく。
(もちろん DB を抽象化してポータブルに作っておく事が要求される場合は別。)
ということで、前置きが長くなったが、 PostgreSQL でいろいろ試したメモ。
これらの各階層で権限の設定ができる。
「複数ユーザ(100 アカウント程度)を想定した場合、どの階層で分断するのが現実的か?」
というのを、改めてマジメに考えてみた。
以下、 アカウント [user] のデータ識別子を [user] とする。
当たり前の結論に至り、なんか安心。
「
好きな果物はなんですか?
A. りんご
B. みかん
C. いちご
...
P. いちじく
」
という問いに対する回答を保存したい場合、
◆RAW に対する CODE の strong / weak points :
[管理系]
O コードと内容との対応を外部で一元管理できるので修正が容易。
X コードと内容との対応表が無いとデータとして成立しない。
[検索系]
O データが簡潔に表せるのでちょっと速いかも。
X 特になし。
[更新系]
O 特になし。
X 特になし。
管理系の視点で CODE のほうが有利と判断する。
これも「正規化」に通じる当たり前の結論。
ただし、コードと内容との対応表(マスターテーブル) の死守が前提。
PHPコードそのもの( array('name'=>'太郎',...) )、
それを serialize(); したもの、あるいは、XML などを想定している。
また、少し毛色が違うが、PostgreSQL の配列型データも、BULK の一種として考える。
◆NORMAL に対する BULK の strong / weak points :
[管理系]
O データ構造とテーブル定義の結合度が低いので、より汎用性がある。
X データを直接操作しにくい ?
=> PostgreSQL の配列型では問題無し。
[検索系]
O 主テーブルを検索するだけで、該当するデータ構造を取得できる。
X 直積を作りにくい ?
=> PostgreSQL の配列型では問題無し。
[更新系]
O 主テーブルを更新するだけで、該当するデータ構造を更新できる。
X データ構造の部分的な更新がしにくい ?
=> PostgreSQL の配列型では問題無し。
総合的に視て、BULK というか「 PostgreSQL の配列型」のほうが有利と判断する。
以下、具体例
MySQL は、システム上必要な場合以外は使っていない。
MySQL が嫌いなわけではなく、
「何かみんな MySQL だなぁ…俺も MySQLer になろうかなぁ。」
と思ったことは数知れず。
でも、PostgreSQL にしかない機能の恩恵に、度々、与ってしまっているので、「乗り換え」には至らず。
それにしても、いろいろな RDBMS があるものだ ( RDBMS比較資料[PDFです] )。
各 RDBMS の特徴は、DB の設計や、チューニングの際に、顕著になるのではないだろうか?
「管理しやすくて、検索が速くて、更新もサクサクできる」
そんな DB はどうしたら実現できるだろうか…と考えていくと、自然と実装の話になっていく。
(もちろん DB を抽象化してポータブルに作っておく事が要求される場合は別。)
ということで、前置きが長くなったが、 PostgreSQL でいろいろ試したメモ。
データのセグメンテーション
PostgreSQL のデータは、cluster ⊃ database ⊃ schema ⊃ tableという階層の最下層であるところの 'table' に保存されるが、
これらの各階層で権限の設定ができる。
「複数ユーザ(100 アカウント程度)を想定した場合、どの階層で分断するのが現実的か?」
というのを、改めてマジメに考えてみた。
以下、 アカウント [user] のデータ識別子を [user] とする。
-
table :
=> create table [user]_table(...); => grant all on [user]_table to [user];
却下
(テーブルの一覧がすごい事になるため)。
-
schema :
$ createuser -P [user]; => /* public は PUBLIC に grant されてるので消す。*/ => drop schema public; => create schema [user] authorization [user];
却下
(
テーブルの一覧には [user] schema に属するテーブルしか現れないが、
スーパーユーザにも見えにくくなるため。
)
-
database :
$ createdb [user]; $ createuser -P [user];
採用
(もっとも現実的)
-
cluster :
$ initdb -D /path/to/[user];
で、ポートを切替えて運用。
…却下でしょう。
当たり前の結論に至り、なんか安心。
選択型データの保存形式
例えば、「
好きな果物はなんですか?
A. りんご
B. みかん
C. いちご
...
P. いちじく
」
という問いに対する回答を保存したい場合、
- RAW: 'りんご'とか'いちご'という内容を保存すべきか?
- CODE: 'A'とか'C'というコードを保存すべきか?
◆RAW に対する CODE の strong / weak points :
[管理系]
O コードと内容との対応を外部で一元管理できるので修正が容易。
X コードと内容との対応表が無いとデータとして成立しない。
[検索系]
O データが簡潔に表せるのでちょっと速いかも。
X 特になし。
[更新系]
O 特になし。
X 特になし。
管理系の視点で CODE のほうが有利と判断する。
これも「正規化」に通じる当たり前の結論。
ただし、コードと内容との対応表(マスターテーブル) の死守が前提。
データ構造の保存
例えば、members = [ { 'name': '太郎', 'gender': '男' 'fruits': [1, 3] }, { 'name': '花子', 'gender': '女' 'fruits': [2, 3, 11] } ];というデータ構造を保存したい場合、
-
NORMAL:
データの値 1 つをフィールド 1 つに( 1 対 1 に)保存するべきか?
上の例の場合、正規化後のテーブルは 3 つか 4 つになるはず。
-
BULK:
上の例(意図的に JSON で記述してある)のように、
「データのラベルや値を含む構造そのものを適切に表現する文字列」
として保存するべきか?
PHPコードそのもの( array('name'=>'太郎',...) )、
それを serialize(); したもの、あるいは、XML などを想定している。
また、少し毛色が違うが、PostgreSQL の配列型データも、BULK の一種として考える。
◆NORMAL に対する BULK の strong / weak points :
[管理系]
O データ構造とテーブル定義の結合度が低いので、より汎用性がある。
X データを直接操作しにくい ?
=> PostgreSQL の配列型では問題無し。
[検索系]
O 主テーブルを検索するだけで、該当するデータ構造を取得できる。
X 直積を作りにくい ?
=> PostgreSQL の配列型では問題無し。
[更新系]
O 主テーブルを更新するだけで、該当するデータ構造を更新できる。
X データ構造の部分的な更新がしにくい ?
=> PostgreSQL の配列型では問題無し。
総合的に視て、BULK というか「 PostgreSQL の配列型」のほうが有利と判断する。
以下、具体例
- NORMAL の場合:
create table fruit ( fruit_id serial, name text ); create table member ( member_id serial, name text, gender text ); create table fruit_to_member ( fruit_to_member_id serial, member_id integer, fruit_id integer ); insert into fruit(name) values('りんご'); insert into fruit(name) values('みかん'); insert into fruit(name) values('いちご'); insert into member(name,gender) values('太郎','男'); insert into member(name,gender) values('花子','女'); -- make relations; insert into fruit_to_member(member_id,fruit_id) values(1,1); insert into fruit_to_member(member_id,fruit_id) values(1,3); -- make another relations; insert into fruit_to_member(member_id,fruit_id) values(2,2); insert into fruit_to_member(member_id,fruit_id) values(2,3); select * from member,fruit where fruit.fruit_id in ( select fruit_id from fruit_to_member where fruit_to_member.member_id = member.member_id ); member_id | name | gender | fruit_id | name -----------+------+--------+----------+-------- 1 | 太郎 | 男 | 1 | りんご 1 | 太郎 | 男 | 3 | いちご 2 | 花子 | 女 | 2 | みかん 2 | 花子 | 女 | 3 | いちご (4 rows) Time: 0.784 ms
- BULK の場合:
create table fruit ( fruit_id serial, name text ); create table member ( member_id serial, name text, gender text, fruit smallint[] ); insert into fruit(name) values('りんご'); insert into fruit(name) values('みかん'); insert into fruit(name) values('いちご'); -- make record, with ARRAY; insert into member(name,gender,fruit) values('太郎','男','{1,3}'); -- make another record, with ARRAY; insert into member(name,gender,fruit) values('花子','女','{2,3}'); /* * where 2 = ANY(some_array) * (古い記法: where some_array *= 2) */ select * from member,fruit where fruit.fruit_id = ANY(member.fruit) order by member_id; member_id | name | gender | fruit | fruit_id | name -----------+------+--------+-------+----------+-------- 1 | 太郎 | 男 | {1,3} | 1 | りんご 1 | 太郎 | 男 | {1,3} | 3 | いちご 2 | 花子 | 女 | {2,3} | 2 | みかん 2 | 花子 | 女 | {2,3} | 3 | いちご (4 rows) Time: 0.506 ms
感想
たまにマニュアルを読むと幸せになれる…と信じよう。ツッコミ
- 1: master (12/22 12:27)
- PostgreSQL 7.4 で、配列型の関数などが一気に増えたようで、
where ':' || array_to_string(some_array,':') || ':' ~ ':(1|2):'
なんて事もできる。
バージョンも気にしないと。
http://www.postgresql.org/docs/current/static/release-7-4#AEN76154
サーバ管理その1
tf-idf + bayesian-filter を試したいので、このサーバに chasen とか mecab とか入れる事にした。
で、かなり放置していたので、いろいろと整備した。
以下、メモ:
ports の実体はスケルトン。↓こんな感じ。
で、portupgrade っていう管理ユーティリティがあって便利。 linux の apt-get に相当する。
portinstall / portupgrade の再に現れる CUI で、大抵の config オプションを設定できる。
( ports で管理できる config オプションを 'knob' と呼ぶらしい。)
設定を変えて再インストールしたい場合とかは、
今回は、先ず、いろいろアップグレードした。
それから、無くて困っていた screen をインストールした。
FreeBSD Portsで cvs から 'screen' を検索して、それが /usr/ports の下にあることを確認して、
参考:
これも、ついでにアップグレード。
(apache-1.3.34 も出ているが、これは Apache-SSL が出るまで待つことにした。)
[backup]
参考:
実は結構ハマった。
本題の chasen, mecab を、src, ports のどっちで管理するかも要検討。
で、かなり放置していたので、いろいろと整備した。
以下、メモ:
ports
packageはコンパイル済だが、ports は未コンパイル。その分、強力。ports の実体はスケルトン。↓こんな感じ。
$ tree /usr/ports/graphics/ImageMagick/ /usr/ports/graphics/ImageMagick/ |-- Makefile |-- distinfo |-- files | |-- patch-Makefile.in | |-- patch-coders::jp2.c | `-- patch-configure |-- pkg-descr `-- pkg-plist 1 directory, 7 files
で、portupgrade っていう管理ユーティリティがあって便利。 linux の apt-get に相当する。
$ # ports を最新にする。 $ cvsup -g /usr/local/etc/ports-supfile; $ # ports のデータベースを更新する。 $ portsdb --update --fetchindex; # index は配布されているものを使う。 $ # または、 $ portsdb --update --updateindex; # index も構築する。 $ # または、 $ cd /usr/ports/; make index; # より確実らしい。 $ # ports の内容を表示する。 $ portversion --verbose; $ # ports からインストールする。 (= cd /usr/ports/foo/bar; make install clean; ) $ portinstall --verbose foo/bar; $ # ports からアップグレードする。 $ portupgrade --interactive foo/bar; $ # ports の作業ファイルを削除する。distclean は 2 回指定する。 $ portsclean --workclean --distclean --distclean;
portinstall / portupgrade の再に現れる CUI で、大抵の config オプションを設定できる。
( ports で管理できる config オプションを 'knob' と呼ぶらしい。)
設定を変えて再インストールしたい場合とかは、
$ まず消す。 $ cd /usr/ports/foo/bar; $ make deinstall; $ # config の CUI を使えるかもしれない。 $ make config; # # CUI 使えたら、 $ make reinstall; # # CUI 使えなかったら、 $ # /usr/local/etc/pkgtools.conf の MAKE_ARGS にオプションを指定して、 $ portinstall --verbose foo/bar ;
今回は、先ず、いろいろアップグレードした。
$ portupgrade --interactive --all; $ portsclean --workclean --distclean --distclean;
それから、無くて困っていた screen をインストールした。
FreeBSD Portsで cvs から 'screen' を検索して、それが /usr/ports の下にあることを確認して、
$ portinstall --verbose sysutils/screen; $ portsclean --workclean --distclean --distclean;簡単。
参考:
src からインストール
APP(ApachePostgresqlPhp) は、 src で管理している。これも、ついでにアップグレード。
(apache-1.3.34 も出ているが、これは Apache-SSL が出るまで待つことにした。)
- postgresql-8.1.1
- php-4.4.1
- ZendOptimizer-2.6.0
- php-json-ext-1.1.0
[backup]
pg_dumpall -g > /home/postgres/backup/all.dmp; pg_dump -b -F c foo > /home/postgres/backup/foo.dmp;[restore]
psql -f all.dmp template1 pg_restore -d foo foo.dmpで、無事完了。
参考:
ハマりどころ
最近 PHP のリリースが安定していないので、必要以上にビビっていたせいもあり、実は結構ハマった。
-
- $ pkgdb -F;
- このサーバの構築に際して、上記 APP などを src で管理するために、
VPS7 の標準構成から package/ports 版をアンインストールして頂いた。
その際、PHP の拡張(php4-xxx) の package/ports が取り残されていたらしく、
存在しない apache との依存関係を引きずっているようだった。
とりあえず、$ pkgdb -F;
したら問題無さそう。
-
- autoconf,automake,libtool の重複
- ひとしきり portupgrade/portsclean して、
$ portversion --verbose;
してみたら、autoconf,automake,libtool がバージョン違いで複数ある。
不安に思いつつ、PHP を src からインストールする作業に取り掛かると、
configure で warning が出て、make も失敗。*** Warning: inter-library dependencies are not known to be supported. *** All declared inter-library dependencies are being dropped. *** Warning: libtool could not satisfy all declared inter-library *** dependencies of module libphp4. Therefore, libtool will create *** a static module, that should work as long as the dlopening *** application is linked with the -dlopen flag.
package/ports のツリーがイカレたか?
と思ったが、重複自体は問題ないらしい。
package/ports 間の依存関係の連鎖を最小限にするために、
被依存バージョンを残しつつ、別のバージョンもインストールする方針らしい。
とりあえず、libtool とかが見つからないのはマズい気がしてタマらなかったので、
$ ln -s /usr/local/bin/libtool15 /usr/local/bin/libtool
とか、しばらくゴニョゴニョやってたら、なんかコンパイルできた。
途中、不安が不安を呼んで、
config.log の fail とか warn とかの多さにくじけそうになったが、
もともと config.log は、そういうものらしいし、とりあえず動いてるのでヨシ。
本題の chasen, mecab を、src, ports のどっちで管理するかも要検討。
トラックバック
(1)ツッコミ
- 1: master (12/16 17:56)
- その後、PECL の filter を入れようとしたら、make でこけた。
PHP 変わり過ぎ。
拡張で提供されるはずの関数の API 真似て、関数を自作しといて、
安定したら乗り換えるとか…無謀か。 - 2: master (12/17 14:19)
- ちなみに、PRCL の chasen はコンパイルできたんだけど、
使うとセグメンテーションエラーで落ちる。
しかたないので、システム関数で呼んでおきます。
理解/説明
「ソレは何か?」
という問いに対して応えるために必要な作業は、
客観的に知覚できる限りの差異で
「ソレ」を「ソレ以外」から区別する作業ではなく、
問者の主観的なシナリオの中に抽象化された
「ソレ」と「ソレ以外」との関係性を描く作業である。
そのためには、
その関係性を描くシナリオに、
問者のシっている「ソレ以外」を登場させ、それを足場にするか、
あるいは、
そのシナリオ自体と、
問者のシっている別のシナリオとの類似性を頼りにするか、
いずれにせよ、
問者のシっている物事から「ソレ」へと、想像を及ばせる事になるだろう。
こういう作業のツールとしては、モデルが有効だ。
モデルを表現するのに最適なのは視覚化であり、
その中でもよく使われるのは模式図(2次元的な視覚化)である。
特定の状況を表す模式図においては、
その状況に登場する要素は
「名前」、「アイコン」、「変数」などの抽象化された記号で表され、
各要素間の関係性だけが視覚化される。
各要素の内部構造は--- その要素自体の性質の由来であるが ---、
また別の模式図で表されるべきものである。
物事の「記録/再生」は、あるいは「理解/説明」は、
いずれこのような作業だと思う。
そして、これこそプログラミングの本質ではないだろうか?
抽象化に関する、能力と、センスと、情熱には、個人差があり、
手法、ツールがそれを反映しているのだろうと思う。
抽象化/記号の発明は偉大だ。
という問いに対して応えるために必要な作業は、
客観的に知覚できる限りの差異で
「ソレ」を「ソレ以外」から区別する作業ではなく、
問者の主観的なシナリオの中に抽象化された
「ソレ」と「ソレ以外」との関係性を描く作業である。
そのためには、
その関係性を描くシナリオに、
問者のシっている「ソレ以外」を登場させ、それを足場にするか、
あるいは、
そのシナリオ自体と、
問者のシっている別のシナリオとの類似性を頼りにするか、
いずれにせよ、
問者のシっている物事から「ソレ」へと、想像を及ばせる事になるだろう。
こういう作業のツールとしては、モデルが有効だ。
モデルを表現するのに最適なのは視覚化であり、
その中でもよく使われるのは模式図(2次元的な視覚化)である。
特定の状況を表す模式図においては、
その状況に登場する要素は
「名前」、「アイコン」、「変数」などの抽象化された記号で表され、
各要素間の関係性だけが視覚化される。
各要素の内部構造は--- その要素自体の性質の由来であるが ---、
また別の模式図で表されるべきものである。
物事の「記録/再生」は、あるいは「理解/説明」は、
いずれこのような作業だと思う。
そして、これこそプログラミングの本質ではないだろうか?
抽象化に関する、能力と、センスと、情熱には、個人差があり、
手法、ツールがそれを反映しているのだろうと思う。
抽象化/記号の発明は偉大だ。
[ このエントリへはツッコミ出来ません ]