テキストリレーションシップの構築 |
- 近年、データベースといえばリレーショナルデータベースを差すほど世界標準になっています。
これは、リレーショナルデータベース自体が高度な機能を持っている事に他なりませんが、
一般的にレンタルサーバでホームページを運営する場合はほとんどすべてのプロバイダが許可していません。
また、多くのプロバイダで使用されているUNIXでは使用も困難です。
次章ではMySQLを使ったホームサーバでの本格的なデータベースアクセスも紹介しますが、
ここでは、本格的なリレーショナルデータベースには及ばないまでも
テキストデータでリレーションを構築し大量のデータを少しでも効率良く、
高速に動作させる方法を考えてみましょう。
- リレーションとは
通常のテキストファイルで全国の名所、名産品を管理するデータベースを構築する場合、
高知県 | 名所旧跡 | 高知城 | 国の重要文化財に指定されている四国の名城 |
高知県 | 名所旧跡 | 桂浜 | 雄大な太平洋に面した月の名所 |
高知県 | 名所旧跡 | 竜河洞 | 延長4,000m内公開1,000mの龍河洞は、
およそ1億7,500万年前、海中より隆起した鍾乳洞 |
徳島県 | 名所旧跡 | 鳴門渦潮 | 瀬戸内海と紀伊水道の干満の差によって生じ、
渦の最も大きいものでは直径20m以上におよび、世界三大潮流とも言われています。 |
このように都道府県名、カテゴリー、施設名、PRと記憶させます。
ご覧いただければ一目でわかると思いますが、都道府県と、カテゴリーは同じ文字列が並んでいます。
数百件のデータ量ではそれほど問題ではありませんが、数千、
数万件ともなると大変無駄な領域でそれだけサーバの負担も大きくなります。
そこで都道府県名とカテゴリーを別のファイルに分けて増え続けるデータファイルにはそれぞれのコード番号を記憶させるのです。
都道府県リスト |
0 | 北海道 |
1 | 青森県 |
2 | 秋田県 |
・・ |
37 | 徳島県 |
38 | 高知県 |
・・ |
46 | 沖縄県 |
|
カテゴリーリスト |
0 | 名産品 |
1 | 名所旧跡 |
2 | レジャー施設 |
3 | 文化施設 |
4 | 宿泊施設 |
5 | お食事処 |
6 | 交通施設 |
7 | 行政施設 |
|
このようなコード付きマスターファイルを作成しておけば同じデータファイルも以下のように置き換えられます。
38 | 1 | 高知城 | 国の重要文化財に指定されている四国の名城 |
38 | 1 | 桂浜 | 雄大な太平洋に面した月の名所 |
38 | 1 | 竜河洞 | 延長4,000m内公開1,000mの龍河洞は、およそ1億7,500万年前、
海中より隆起した鍾乳洞 |
37 | 1 | 鳴門渦潮 | 瀬戸内海と紀伊水道の干満の差によって生じ、
渦の最も大きいものでは直径20m以上におよび、世界三大潮流とも言われています。 |
これで1件あたり約10バイトの節約になります。
1万件のデータファイルでは10万バイト、約5万文字節約したことになります。
当然、高速に動作するということですね。
- 抽出のための工夫
高速に動作させるためデータ量を減らしたのですから高速に検索、抽出できなければなりません。
前記のデータから「高知県」の「名所旧跡」を抽出するには、
foreach $line (@DATA) {
($area, $category, $facility, $pr) = split(/\t/, $line);
if ($area == 38 && $category == 1) { push(@MATCH, $line); }
}
|
これは、@DATAのすべてのデータをforeachループで1つづつ調べてマッチしたものを@MATCHに格納しています。
キーワードを指定して文字列から検索する場合はこの方法しかありませんが、
コード番号の場合はもっと高速に動作するステートメントがperlには存在します。
●grep関数を使う
grep関数は、
@MATCH = grep(/条件/, 配列);
の書式で使用し、「条件」はperlのマッチ演算子が使用できます。
●検索キーを付ける
データファイルからコード番号で抽出するには、どのフィールドのコードかを指定する必要があります。
38 | 1 | 高知城 | 国の重要文化財に指定されている四国の名城 |
このデータからコード番号「38」を検索しようとしても都道府県のコードなのか、カテゴリーからなのかがわかりません。
そこで、リレーションが必要なフィールドにはキーをつけて記憶させておきます。
area=38 divi=1 高知城 国の重要文化財に指定されている四国の名城
※キーにあまり長い名前を付けるとリレーションにしてデータを圧縮する意味がなくなります。
grepを使用して前記のコードと全く同じ結果を得るコードは、
@MATCH = grep(/area=38\t/, @DATA); ←道府県で抽出
@MATCH = grep(/divi=1\t/, @MATCH); ←都道府県抽出データからカテゴリーを抽出
このように、わずか2行で実現でき、なんといっても圧倒的に高速に抽出できます。
【注意】
grep関数の検索条件に日本語を使用することはできません。
したがってフィールドのキーに日本語を使用することもできないと言うことになります。
- 結果の置き換え
抽出された結果をブラウザに出力する場合は、それぞれのコードを置き換える必要があります。
都道府県のテーブルが、
@AREA = (
'北海道','青森県','秋田県','岩手県','宮城県','山形県','福島県','栃木県','新潟県','群馬県',
'埼玉県','茨城県','千葉県','東京都','神奈川県','山梨県','長野県','岐阜県','富山県','石川県',
'静岡県','愛知県','三重県','奈良県','和歌山県','福井県','滋賀県','京都府','大阪府','兵庫県',
'岡山県','鳥取県','島根県','広島県','山口県','香川県','徳島県','愛媛県','高知県','福岡県',
'佐賀県','大分県','熊本県','宮崎県','長崎県','鹿児島県','沖縄県'
);
|
と@AREA配列変数に格納されていて、カテゴリーが、
@CATEGORY = ('名産品','名所旧跡','レジャー施設','文化施設','宿泊施設','お食事処','交通施設','行政施設');
|
のように@CATEGORY配列変数に保存されている場合は、
print "<table border=1>\n";
foreach $line (@MATCH) {
($area, $category, $facility, $pr) = split(/\t/, $line);
$area =~ s/area=//; ←キーを削除して都道府県コードを抽出
$category =~ s/divi=//; ←キーを削除してカテゴリーコードを抽出
print "<tr><td>$AREA[$area]</td>\n";
print "<td>$CATEGORY[$category]</td>\n";
print "<td>$facility</td>\n";
print "<td>$pr</td></tr>\n";
}
print "</table>\n";
|
こうすればコードで記憶されていたデータを元の文字列に置き換えて表示することができます。
|
|