高速化する

 前項では巨大なデータを一括して読み込んでいるため処理に時間がかかっていました。そこで、12万件のデータを0〜9で始まる郵便番号順に10個のファイルに分割します。これで5MBのファイルも平均して400KB程度にサイズが減少します(最大のものは900KB近くになりますが)。ここまで減少すれば郵便番号が入力されてからデータを読み込み検索処理を行っても大丈夫そうです。
 まず、Photoshop CSを使って10分割するJavaScriptを実行します(サンプルファイルをダウンロードする)。実行前には郵便番号データを変換したKEN.txtをルートディレクトリに用意しておきます。処理が終了するとルートディレクトリに0.txt〜9.txtのファイルが作成されます。このファイルをサブフォルダzipcodeに、まとめて入れておきます。あとは、検索ボタンが押されたら郵便番号の先頭の番号をキーにして対応するデータを読み込みます。検索処理は全く同じです。(サンプルを実行する

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=shift_jis">
<title>郵便番号検索(郵便番号に応じて読み込み処理)</title>
<script type="text/javascript" src="xmlhttp.js"></script>
<script type="text/javascript"><!--
zipData = "";
function loadDataFile(fName)
{
httpObj = createXMLHttpRequest(displayData);
if (httpObj)
{
httpObj.open("GET",fName,true);
httpObj.send(null);
}
}
function displayData()
{
if ((httpObj.readyState == 4) && (httpObj.status == 200))
{
parseZIPCode(httpObj.responseText);
}else{
$("result").innerHTML = "郵便番号データを読み込み中...";
}
}
// 読み込むファイル名を設定
function findZipCode()
{
var n = $("zipCode").value.charAt(0); // 先頭の番号を取得
loadDataFile("zipcode/"+n+".txt");
}
// カンマ区切りテキストを解析して一致したデータを表示
function parseZIPCode(zipData)
{
var resultText = "";
var LF = String.fromCharCode(10); // 改行コード (LF)
var zipNum = $("zipCode").value;
lineData = zipData.split(LF);
for (var i=0; i<lineData.length; i++)
{
var itemData = lineData[i].split(",");
var ptr = itemData[0].indexOf(zipNum);
if (ptr > -1) resultText +=itemData[1]+"<br>";
}
if (resultText == "") resultText = "該当する住所はありません";
$("result").innerHTML = resultText;
}
// --></script>
</head>
<body>
<h1>郵便番号検索(郵便番号に応じて読み込み処理)</h1>
<form name="ajaxForm" onSubmit="findZipCode();return false">
<input type="text" value="3990711" id="zipCode">
<input type="button" value="検索" onClick="findZipCode()"><br>
</form>
<div id="result"></div>
</body>
</html>

 データを10分割しましたが、まだ反応が悪い場合もあります。そこで、スクリプトを使って100分割します(実際のサンプルをダウンロードする)。つまり先頭の2桁の郵便番号に対応した「番号.txt」ファイルを作成します。やはりPhotoshop CSを使って分割処理を行います。ルートディレクトリにはKEN.txtを用意し、ルートディレクトリにフォルダzipcodeを作成しておきます。このzipcodeフォルダ内に分割されたデータが入ります。なお、処理後に0.txt〜9.txtは先頭に0を付加し00.txt〜09.txtとしておきます。
 実際のスクリプトは以下のようになります。(サンプルを実行する

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=shift_jis">
<title>郵便番号検索(郵便番号に応じて読み込み処理2)</title>
<script type="text/javascript" src="xmlhttp.js"></script>
<script type="text/javascript"><!--
function loadDataFile(fName)
{
httpObj = createXMLHttpRequest(displayData);
if (httpObj)
{
httpObj.open("GET",fName,true);
httpObj.send(null);
}
}
function displayData()
{
if ((httpObj.readyState == 4) && (httpObj.status == 200))
{
parseZIPCode(httpObj.responseText);
}else{
$("result").innerHTML = "郵便番号データを読み込み中...";
}
}
// 読み込むファイル名を設定
function findZipCode()
{
var n = $("zipCode").value.substring(0,2); // 先頭の番号2桁を取得
if (n.length < 2) return; // 1桁の場合は処理しない
loadDataFile("zipcode2/"+n+".txt");
}
// カンマ区切りテキストを解析して一致したデータを表示
function parseZIPCode(zipData)
{
var resultText = "";
var LF = String.fromCharCode(10); // 改行コード (LF)
var zipNum = $("zipCode").value;
lineData = zipData.split(LF);
for (var i=0; i<lineData.length; i++)
{
var itemData = lineData[i].split(",");
var ptr = itemData[0].indexOf(zipNum);
if (ptr > -1) resultText +=itemData[1]+"<br>";
}
if (resultText == "") resultText = "該当する住所はありません";
$("result").innerHTML = resultText;
}
// --></script>
</head>
<body>
<h1>郵便番号検索(郵便番号に応じて読み込み処理2)</h1>
<form name="ajaxForm" onSubmit="findZipCode();return false">
<input type="text" value="3990711" id="zipCode">
<input type="button" value="検索" onClick="findZipCode()"><br>
</form>
<div id="result"></div>
</body>
</html>

 100分割すると、さすがにサイズが小さくなるため読み込みも検索も高速になります。これで、普通に使えるようになりました。あとは、Ajaxを使った他の郵便番号検索サイトでもやっているリアルタイムに入力したら即結果が表示できるようにします。これはサーバー側の処理の部分でも使ったタイマーを利用します。やはりbodyタグのonload〜を追加するだけです。(サンプルを実行する

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=shift_jis">
<title>郵便番号検索(リアルタイムに処理)</title>
<script type="text/javascript" src="xmlhttp.js"></script>
<script type="text/javascript"><!--
oldTxt = "";
function loadDataFile(fName)
{
httpObj = createXMLHttpRequest(displayData);
if (httpObj)
{
httpObj.open("GET",fName,true);
httpObj.send(null);
}
}
function displayData()
{
if ((httpObj.readyState == 4) && (httpObj.status == 200)) parseZIPCode(httpObj.responseText);
}
// 読み込むファイル名を設定
function findZipCode()
{
var txt = $("zipCode").value; // 先頭の番号2桁を取得
var n = txt.substring(0,2); // 先頭の番号2桁を取得
if (n.length < 2)
{ // 1桁の場合は結果をクリアして以後は処理しない
$("result").innerHTML = "";
return;
}
if (txt== oldTxt) return; // 番号が同じ場合も処理しない
loadDataFile("zipcode2/"+n+".txt");
oldTxt = txt;
}
// カンマ区切りテキストを解析して一致したデータを表示
function parseZIPCode(zipData)
{
var resultText = "";
var LF = String.fromCharCode(10); // 改行コード (LF)
var zipNum = $("zipCode").value;
lineData = zipData.split(LF);
for (var i=0; i<lineData.length; i++)
{
var itemData = lineData[i].split(",");
var ptr = itemData[0].indexOf(zipNum);
if (ptr > -1) resultText +=itemData[1]+"<br>";
}
if (resultText == "") resultText = "該当する住所はありません";
$("result").innerHTML = resultText;
}
// --></script>
</head>
<body onload='setInterval("findZipCode()",500)'>
<h1>郵便番号検索(リアルタイムに処理)</h1>
<form name="ajaxForm" onSubmit="findZipCode();return false">
<input type="text" value="3990711" id="zipCode">
<input type="button" value="検索" onClick="findZipCode()"><br>
</form>
<div id="result"></div>
</body>
</html>

 これで一応郵便検索ができました。と言っても最初の項に書いたように問題点もあります。解決するには最初のデータベースを変換する際に、ちゃんとした処理を行います。
 データサイズが大きいものは、処理の方法を工夫することでサーバーにも負荷がかからず、高速に処理させることもできます。もちろん、うまくいかないデータの場合もありますが、そのような場合はサーバー側とクライアント側で、うまく処理を分ければよいでしょう。

[目次へ]

(2006.1.28)