IPv6 Access Checker @yadiary.net You accessed over SSL connection.


CouchDBを使用した郵便番号検索

Tweet

日本郵便が公開している郵便番号CSVファイルを使用し、CouchDBを使ったアプリケーションの具体例として郵便番号検索システムを作成しています。
コードなどはまとめて公開したいとは思っていますが時期は未定です。 断片的な成果についてはBlogに反映させています。

郵便番号検索 Ver. 1.8 (2015/01/18 Updated)

プログラムコードの公開と解説の準備

Ver. 1.8の特徴・変更点

バックエンドのライブラリをYALToolsベースに変更しています。

その他のリリース後の修正点は「変更履歴」をご覧下さい。

利用について

当システムはデータベースエンジンにApache CouchDBを使用した郵便番号の検索システムです。

このシステムはCouchDBの実証テストを主な目的としており、使い勝手などについては他の郵便番号検索システムとは異なる部分があります。

郵便番号から住所を検索する他に、全国から同名の市町村を検索するなど、郵便番号データベースをいくつかの角度から検索できるようにしています。

また mode=search_json をリクエストに追加することで、理時間などのフィールドを追加したCouchDBが出力するJSON形式で返す事もできます。

制限事項

データは郵便番号情報を元にし、前方一致で検索する仕組みになっている都合上、複数の地域が登録されている場合には、検索結果に表示されない場合があります。 (例:921-8046 「法師山、坊山、マ、鱒川淵、ム、元末、元涌波庚、ヤ、リ、ル、レ乙、」の場合、途中の「ム」などを入力しても結果に表示されません)

複数の検索条件を指定した場合の振舞いについて

郵便番号の前3桁と後4桁を入力した場合、その他の検索項目を条件に加えることはできません。

また郵便番号(前3桁、又は、後4桁)を含めて3つ以上の項目を条件とする事はできません。 3つの検索条件は「都道府県」、「市区郡」、「町村」の組み合せについてのみ行なえます。

現時点では2つまでの項目について、ほぼ全ての組み合せで検索ができるようになっています。

利用している外部ライブラリについて

本システムで利用しているライブラリは次のとおりです。

CSSライブラリ
Blueprint CSS v1.0
JavaScriptライブラリ (イベントハンドリング、タブ表示)
jQuery v1.4.4
jQuery UI 1.8.6
動的入力補完ボックス (jQuery plugin)
FlexBox v0.9.6 + search-by-key patch

利用にあたって修正したコードについては、Blog等で解説しているか、する予定です。

検索方法

検索条件の入力欄の上段には半角数字、下段にはカタカナ、あるいは漢字で条件を入力し、検索する事ができます。

下記は郵便番号の前3桁を入力し、195件の結果が得られた事を示しています。
入力例:

2つの条件を指定して検索

下記は2つの条件を入れることで、福島県の「カミ」で始まる郵便番号の割り当てられた地域が61件ある事を示しています。
入力例:都道府県と断片的な町名の入力

サポートしている入力の組み合せ

検索用の入力欄は全部で6つあります(「表示件数」は出力の調整用です)が、 最大3つの入力を組み合せて検索する事ができます。

設計時に想定している組み合せは次の通りです。 "on"は何かしらの文字列が入力されている事を示しています。 "on*"は、入力された文字列が(「福島」などの)一部分ではなく(「福島県」のように)、郵便番号データベースに登録されている内容と完全にマッチする必要があります。

CouchDB内部では、この組み合せそれぞれについて対応するViewを定義しています。

No.郵便番号5桁郵便番号 前3桁郵便番号 後4桁都道府県市区郡町村、その他
1on
2on*on
3on*off
4offon
5onon*
6on*on
7on*on
8offonon*
9offon*on
10offon*on
11offoffon
12onoffoff
13offonoff
14on*offon
15on*onoff
16offon*on
17on*on*on

エラーとなる一般的な例

複数項目を入力する場合には、左側の項目については完全に一致する名称を入力する必要があります。 JavaScriptを有効にしている場合には、補完機能を利用する事ができます。

複数欄へ入力した場合の優先順位については「検索方法::サポートしている入力の組み合せ」にあります。

同一フィールド内でのカナ、漢字の混在

例えば県名に「福シマ」のように、カナと漢字を混在させると検索する事ができません。

フィールドが違う場合、「福島県」、「アイヅ」のような2入力を検索する事は可能です。

「都道府県名」、「市区郡名」、「町村名、その他の地名」欄、全てに入力した場合のエラー

3つの入力項目を選択する場合には、「全て漢字」、あるいは 「全てカナ」でないと検索する事はできません。

カナ、漢字を混ぜて「都道府県名」、「市区郡名」、「町村名、その他の地名」の3つの項目を入力した場合には、全てが空欄の場合と同様に郵便番号が「"965"で始まる条件」での検索結果が表示されます。

入力項目の補完について

「都道府県名」、「市区郡名」、「町村名、その他の地名」についてはカナ、漢字での入力内容に応じて候補が動的に表示されます。

町村名の欄に「カ」を一文字入力し、カで始まる町村名が候補として表示されたところ

「町村名、その他の地名」の補完の際には、「都道府県名」、「市区郡名」など他の欄に入力された内容を参考に候補を表示します。 両方の欄に入力されていた場合には、市区郡名の内容を優先して補完を行ないます。

「市区郡名」についても同様に、「都道府県名」に存在する名称が候補として表示されます。

「都道府県名」については、常にカタカナ、漢字での全候補が表示されます。

注意事項

複数の項目を入力する場合に、右側の欄に入力する内容は完全一致する名称である必要があり、名称の一部である場合には検索が正常に行なわれない場合があります。

入力補完について挙動がおかしくなった場合には入力欄右上の「全入力項目のリセット」のリンクをたどって先頭画面に移動してください。

Ver. 1.6から多くのパラメータ名が変更されています。

処理は全てGETリクエストとパラメータの組み合せにより行なわれています。

パラメータの指定によりJSON形式で出力を取り出す事ができます。

各パラメータの説明

典型的なURLは次のようなものです。

http://www.yadiary.net/postal/main.fcgi?mode=search_json&page=1&unit=5&pref=%E7%A6%8F%E5%B3%B6%E7%9C%8C&city=%E4%BC%9A%E6%B4%A5%E8%8B%A5%E6%9D%BE%E5%B8%82&street=%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E8%A5%BF

Ver. 1.6時点での出力に影響のあるパラメータは次の通りです。 前2つは画面に表示する出力件数の調整のために使います。

mode
省略時は"search"がデフォルト値になります。 この他に"search_json", "search_xml"を指定する事が可能で、それぞれJSON形式、XML形式で出力します。
unit
1画面に何件のデータを表示するかを指定する。1以上の整数。
page
ページ番号に相当する数字。0以上の整数であること。
unit=2,page=2の場合は3,4番目の項目が、unit=2,page=3の場合は5,6番目の項目が出力されます。
code_prefix
郵便番号の前3桁の数字。
code_suffix
郵便番号の後4桁の数字。
old_code_prefix
旧5桁の郵便番号
pref
都道府県名。カタカナ、あるいは、漢字表記。
city
市区郡名。カタカナ、あるいは、漢字表記。
street
市区郡名に続く町名、村名、その他の地名。カタカナあるいは漢字表記。

pref_js, city_js, street_jsパラメータはFlexBox用のパラメータで、内部ではpref, city, streetに値を代入しています。 ブラウザでは2つのパラメータが指定されているようにみえますが、省略可能です。

他のスクリプトからJSON出力を参照する場合の注意点

他のスクリプトから参照する場合に、全ての検索結果を読み込みたい場合にはunitに指定する値を全件数の122977を越える数字を指定する事で"page"の指定を事実上無視し、全データを一度にダウンロードする事ができます。

データ形式について

いまのところデータ形式について詳細は決めていませんが、Ver. 1.6時点での内部構造は次のようになっています。

{
  "rows":[
    {
          "_id":      "90fd89479139d6f3020fe1f9b1d6e80691dda64f",
          "_rev":      "1-75a3aba38cd6d0508c0ead9dd9c63e1e",
          "type":      "pcode",
          "x0401":      "全国地方公共団体コード",
          "p":        "都道府県 (漢字)",
          "pk":       "都道府県 (カタカナ)",
          "c":        "市区郡名 (漢字)",
          "ck":       "市区郡名 (カタカナ)",
          "s":        "町村名、その他の地名 (漢字)",
          "sk":       "町村名、その他の地名 (カタカナ)",
          "code":       "郵便番号 7桁",
          "ocode":      "旧郵便番号 5桁",
          "codep":      "郵便番号 前3桁",
          "codes":      "郵便番号 後4桁",
          "op1":      "一町域が二以上の郵便番号で表される場合の表示",
          "op2":      "小字毎に番地が起番されている町域の表示",
          "op3":      "丁目を有する町域の場合の表示",
          "op4":      "一つの郵便番号で二以上の町域を表す場合の表示",
          "op5":      "更新の表示(注6)(「0」は変更なし、「1」は変更あり、「2」廃止(廃止データのみ使用))",
          "op6":      "変更理由 (「0」は変更なし、「1」市政・区政・町政・分区・政令指定都市施行、「2」住居表示の実施、「3」区画整理、「4」郵便区調整等、「5」訂正、「6」廃止(廃止データのみ使用))"
    }
  ],
  "rows_total":  表示件数,
  "total":  合計件数,
  "elapsed_time":  処理時間
}

Ver. 1.6.からCouchDBの内部形式を変更しました。 現状では従来との互換性を保持せずに、そのままのデータを表示しています。

その他、JSON形式を要求した場合に返す典型的なレスポンスは次の通りです。

結果が0の場合
{"rows":[],"rows_total":0,"total":0,"reason":"no results","elapsed_time":"0.032"}
例外が発生した場合
{"rowss":[],"reason":"hanging-up query","elapsed_time":"0.006","total":0,"total_rows":0}

出力時のContent-Type

json=true出力時のヘッダは Content-Type: application/json; charset=UTF-8 で、可読性を考慮して最後に改行を含んでいます。

出力されたJSON形式は「JSONクライアント例」のアプリケーションで処理できることを確認しています。

XML出力

JavaScriptのXMLHttpRequestから扱うために、XML出力を追加しました。

リクエストに使うクエリの組み立て各項目の意味については、「Queryパラメータ / JSON出力」を参照してください。

データ形式について

データ形式はJSON出力と、ほぼ同じです。 XML出力に合わせるために、"_id", "_rev"タグについては、XMLに合わせてアンダースコアを省いた"id", "rev"に修正しています。

実際の出力は次の通りです。

<?xml version="1.0"?> 
<postal_search_results> 
  <total_rows>5</total_rows> 
  <total>170</total> 
  <reason>ok</reason>
  <elapsed_time>0.051</elapsed_time>
  <row> 
    <id>90fd89479139d6f3020fe1f9b1d6e80691dda64f</id> 
    <rev>1-75a3aba38cd6d0508c0ead9dd9c63e1e</rev> 
    <type>pcode</type> 
    <x0401>07202</x0401> 
    <p>&#x798F;&#x5CF6;&#x770C;</p> 
    <pk>&#x30D5;&#x30AF;&#x30B7;&#x30DE;&#x30B1;&#x30F3;</pk> 
    <c>&#x4F1A;&#x6D25;&#x82E5;&#x677E;&#x5E02;</c> 
    <ck>&#x30A2;&#x30A4;&#x30C5;&#x30EF;&#x30AB;&#x30DE;&#x30C4;&#x30B7;</ck> 
    <s>&#x4EE5;&#x4E0B;&#x306B;&#x63B2;&#x8F09;&#x304C;&#x306A;&#x3044;&#x5834;&#x5408;</s> 
    <sk>&#x30A4;&#x30AB;&#x30CB;&#x30B1;&#x30A4;&#x30B5;&#x30A4;&#x30AC;&#x30CA;&#x30A4;&#x30D0;&#x30A2;&#x30A4;</sk> 
    <code>9650000</code> 
    <ocode>965</ocode> 
    <codep>965</codep> 
    <codes>0000</codes> 
    <op1>0</op1> 
    <op2>0</op2> 
    <op3>0</op3> 
    <op4>0</op4> 
    <op5>0</op5> 
    <op6>0</op6> 
  </row> 
</postal_search_results>

出力時のContent-Type

出力時のヘッダは Content-Type: text/xml; charset=UTF-8 で、可読性を考慮して最後に改行を含んでいます。

出力結果はGoogle Chrome ExtensionからXMLHttpRequestを通してアクセスできる事を確認しています。 完成次第、GitHub,あるいは, Gitoriousにて公開する予定です。

JSONクライアント例

Python 2.6.5 [GCC 4.4.3] on linux2 を使った例です。

本体のmain.pyとライブラリのyapostal.rbの2つのファイルで構成しています。

まずはmain.py部分です。

#!/usr/bin/python 
# -*- coding: utf-8 -*-

import httplib
import json
import sys

if len(sys.argv) != 3:
    print "Usage: %s <code_prefix> <code_suffix>" % (sys.argv[0])
    print "   code_prefix: first three digits"
    print "   code_suffix: last four digits, but clipped number is also ok."
    print ""
    print "   e.x.) %s 382 002" % (sys.argv[0])
    sys.exit(1)
    pass

from yapostal import *

yap = YaPostal()
yap.setCodePrefix(sys.argv[1])
yap.setCodeSuffix(sys.argv[2])
yap.setUnit(10)
yap.setPage(0)

for row in yap.getEachRow():
    print("%(codep)s-%(codes)s %(p)s %(c)s %(s)s" % row)

    pass

sys.exit(0)

ライブラリのyapostal.pyの部分です。同じディレクトリに配置してください。

import httplib
import json

class YaPostal():
    def __init__(self, host = 'stage.yadiary.net', port = 80):
        self.conn = httplib.HTTPConnection('%s:%d' % (host, port))
        self.query = {'mode':'search_json'}
        pass

    def setQuery(self, key, value):
        self.query[key] = value
        pass
    def setCodePrefix(self,code_prefix):
        self.setQuery('code_prefix', code_prefix)
        pass
    def setCodeSuffix(self,code_suffix):
        self.setQuery('code_suffix', code_suffix)
        pass
    def setUnit(self, unit):
        self.setQuery('unit', unit)
        pass
    def setPage(self,page):
        self.setQuery('page', page)
        pass

    def getRows(self):
        query = ""
        for k,v in self.query.iteritems():
            if query != "":
                query += "&%s=%s" % (k,v) 
            else:
                query += "%s=%s" % (k,v)
                pass
            pass
        self.conn.request("GET", "/postal/main.fcgi?" + query)
        self.query['page'] += 1
        
        r1 = self.conn.getresponse()
        return json.loads(r1.read())
    
    def getEachRow(self):
        count = 0
        j = self.getRows()
        max = int(j['total'])
        while max > count:
            for row in j['rows']:
                yield row
                pass
            count += len(j['rows'])
            j = self.getRows()
            pass
        pass
    pass

出力例は次の通りです。

$ ./main.py 382 0022
382-0022 長野県 須坂市 豊丘上町

Ver. 1.8 - 2012/05/06変更点

  • Webサイト全体を、さくらVPSへ移行
  • 移行に合せてCouchDB 1.2.0へバージョンアップ
  • データを作業時最新データ(2012/04/30)に更新
  • 誤字等の修正

【2011/04/17停止】Ver.1.6の特徴

  • バックエンドのライブラリをYALToolsベースに変更
  • CouchDB上のDatabase構造を変更
  • 「都道府県」、「市区郡」、「町村、その他」をカナ、漢字混りで検索した場合のエラー処理が変更
  • 検索用のパラメータ名、cursorpageに変更、他多数
  • JSON周りの変更点多数

ToDo

【2011/03/25停止】Ver.1.5の特徴

  • FlexBoxでの都道府県のリストを北海道から沖縄の順に変更
  • FlexBoxからのQueryを処理するFastCGIスクリプトのbrush-up
  • FlexBoxのキャッシュ構造の改良
  • FlexBox改造部分のコード公開
  • Facebook, Twitterボタンを追加しました

【2010/12/29停止】Ver.1.4の特徴

  • 市区郡名の入力にも都道府県名をベースにした補完機能を追加
  • 町村名の補完に市区郡名の情報も利用する機能を追加
  • 「都道府県名」、「市区郡名」、「町村名」の3項目全てを入力した場合の挙動を改善

【2010/12/14停止】Ver.1.3の特徴

  • FlexBoxを使用した動的候補表示による入力サポート
  • 項目毎に漢字、カタカナを任意の組み合せ(例:県名:「サイタマケン」、市名:「大」等)の入力をサポート
  • JSON出力選択時に、JSON形式でのエラーレスポンスをサポート
  • その他、多くのバグの修正

Created: 2010-12-04, Last modified: 2012-05-06

Copyright © 2010-2012 Yasuhiro ABE <yasu@yasundial.org>

Valid XHTML + RDFa 正当なCSSです!
RDFa it (RDF/XML)!