# \d kenpg_seesaa_list Table "public.kenpg_seesaa_list" +-----------+------+-----------+ | Column | Type | Modifiers | +-----------+------+-----------+ | ymd | date | | | url | text | | | title | text | | | tags | text | | | html_file | text | | | html | text | |列htmlには不要部分も多いので、文字検索に必要な部分だけ切り出して新しい列にします。空の列をテーブルに追加し(列名body)、各種の列制約も付加。↓<- contents +-----------+------+-----------+
# alter table kenpg_seesaa_list add body text;
# alter table kenpg_seesaa_list add primary key (ymd);
alter table kenpg_seesaa_list alter url set not null;
alter table kenpg_seesaa_list alter title set not null;
alter table kenpg_seesaa_list alter tags set not null;
alter table kenpg_seesaa_list alter html_file set not null;
alter table kenpg_seesaa_list alter html set not null;
create unique index on kenpg_seesaa_list (url);
# \d kenpg_seesaa_list
Table "public.kenpg_seesaa_list"
+-----------+------+-----------+
| Column | Type | Modifiers |
+-----------+------+-----------+
| ymd | date | not null |
| url | text | not null |
| title | text | not null |
| tags | text | not null |
| html_file | text | not null |
| html | text | not null |
| body | text | |
+-----------+------+-----------+
Indexes:
"kenpg_seesaa_list_pkey" PRIMARY KEY, btree (ymd)
"kenpg_seesaa_list_url_idx" UNIQUE, btree (url)
# select ymd, left(r[1], 30) || '...' || right(r[1], 30) from kenpg_seesaa_list, regexp_matches(html, 'main_article">(.+)' || '\s+ ') as r order by random(); +------------+-----------------------------------------------------------------------------------------------------------------------------+ | ymd | ?column? | +------------+-----------------------------------------------------------------------------------------------------------------------------+ | 2015-01-06 | 構文比較のメモ。正確には PostgreSQL の配列型と ...QL の CASE 句と違うので、これも間違いやすいところ。 | | 2014-11-22 | 前のブログ\s+
| | 2014-11-10 |
| | 2014-10-28 | | | 2014-12-06 | | | 2014-11-06 | | | 2015-01-16 | PostgreSQL の xpath 関数を使っていると、例...hes の結果が配列でなく複数行なので、少し長くなりました。 | | 2014-10-31 | 10月31日に PostGIS ラスタについて話すというか講...を ST_ColorMap で使う(2)
| ... (196 rows)切り出し結果だけ見ると良さげだけど、行数が196。全記事数は693で、この正規表現ではマッチしないのが相当あるっぽい。でも、UPDATE時はマッチした行だけ変わる(非マッチ行には、元と同じNULLが再入力される)ので、とりあえず入力しちゃいます。SELECT ... FROMからUPDATE ... SETの文に組み替えるだけ。↓ 処理残は、切り出し後の列bodyがNULLの行を数えます(497行)。
# update kenpg_seesaa_list set body = (regexp_matches(html, 'main_article">(.+)' || ' '))[1];UPDATE 196 # select count(*) from kenpg_seesaa_list where body is null; +-------+ | count | +-------+ | 497 | +-------+ (1 row)残った分につき、また正規表現をいくつか試すと ↓ こんな感じで本文を抽出できました。上と同様にUPDATEしますが、念のため更新対象の行をWHERE body is nullと絞り込み。でないと、先に入力済みの行を誤って上書きするかもしれないので。(まぁその時は先のクエリを再実行すればいいけど。SQLはこのへん気楽です)
# select ymd, left(r[1], 30) || '...' || right(r[1], 30) from kenpg_seesaa_list, regexp_matches(html, 'line-height:1.6">\s+(.+)') as r where body is null order by random(); +------------+-----------------------------------------------------------------------------------------------------------------------------+ | ymd | ?column? | +------------+-----------------------------------------------------------------------------------------------------------------------------+ | 2014-04-20 | 再帰クエリの簡単な例として。実行環境は \s+(.+)'))[1] where body is null; UPDATE 497 ![]()
UPDATEの結果497行が変更され、処理残は一気に解消。HTML切り出しのパターンは結局2つで、旧ブログの最初/小リニューアル後それぞれが同じでした。途中で細々と変更してなくてよかった...。
# select count(*) from kenpg_seesaa_list where body is null; +-------+ | count | +-------+ | 0 | +-------+ (1 row)(余談)記事の長さの度数分布を出してみる
今日の作業はここまで。ちょっと物足りないので、抽出した記事本文の長さ(文字数。非ASCIIも1字)の度数分布をSQLで出してみます。 パーセンタイルだと「度数を等しくした区分」ですが、度数分布は普通「数値間隔を等しくした区分」でのカウント。PostgreSQLでは直接出す関数がないので範囲型を使い、少し長いクエリに ↓ なりました。改良できたら追記します。# with a (len) as ( select length(body) from kenpg_seesaa_list ), b (min, max) as ( select min(len), max(len) from a ), c (brk) as ( select min + (max - min) * generate_series(0, 0.875, 0.125) from b ), d (rng) as ( select numrange(brk, lead(brk) over(order by brk)) from c ) select lower(rng), upper(rng), count(len) from a, d where rng @> len :: numeric group by 1, 2 order by 1; +-----------+-----------+-------+ | lower | upper | count | +-----------+-----------+-------+ | 221 | 3228.625 | 314 | | 3228.625 | 6236.250 | 298 | | 6236.250 | 9243.875 | 56 | | 9243.875 | 12251.500 | 16 | | 12251.500 | 15259.125 | 2 | | 15259.125 | 18266.750 | 2 | | 18266.750 | 21274.375 | 4 | | 21274.375 | | 1 | +-----------+-----------+-------+ (8 rows)最後の行は、本当は範囲の上限(全体での最大値)が入るべきところ、クエリがさらに面倒になるので省きました。これ見ると200~20000で右裾にかなり広いです。たまに1万字以上もあったり。たぶんQtアプリのソースをまとめて載せた回じゃないかな。 次回HTMLの不要部分を削除or置換したら、同様の度数分布を出してみます。まぁ大勢は変わらないと思いますけど。