From 0bd6100aecb451ad9ce87c8f8f12ef89404035c1 Mon Sep 17 00:00:00 2001 From: "Kamata, Ryo" Date: Thu, 20 Jan 2022 11:49:53 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=97=E3=83=AA=E3=83=AD=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E7=AD=89=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20(#141)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix local data source bug * Update readme * Fix regex to convert file URL to path Co-authored-by: kamataryo --- .gitignore | 2 ++ README.md | 38 +++++++++++++++++++++++++++++++++++++- package.json | 2 +- src/lib/cacheRegexes.ts | 4 ++++ src/main-node.ts | 16 ++++++++++++---- test/preload.test.ts | 20 +++++++++++++------- 6 files changed, 69 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 0b4577ba44..3ab7d74aac 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ yarn-error.log* // Use npm yarn.lock + +test/*.zip diff --git a/README.md b/README.md index 2e4dca0a20..3f93383ea4 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,42 @@ normalize('北海道札幌市西区24-2-2-3-3', {level}).then(result => { }) ``` +### オプション + +#### `config.townCacheSize: number` + +@geolonia/normalize-japanese-addresses は市区町村毎の最新の町丁目のデータを web API から取得し住所の正規化を行います。 `townCacheSize` オプションはキャッシュする市区町村の数を変更します。デフォルトは 1,000 件になっています。 + +#### `config.preloadCache?: boolean` + +全ての市区町村の町丁目のキャッシュをプリロードするかどうかを指定します。このオプションは Node.js でのみ有効です。`true` が指定された場合 `townCacheSize` の値を無視して無制限にキャッシュを作成します。キャッシュはプロセスの終了の際に破棄されます。 + +#### `config.japaneseAddressesApi: string` + +町丁目データを配信する web API のエンドポイントを指定します。デフォルトは `https://geolonia.github.io/japanese-addresses/api/ja` です。この API から配信されるデータのディレクトリ構成は [Geolonia 住所データ](https://github.com/geolonia/japanese-addresses/tree/develop/api)を参考にしてください。 + +`japaneseAddressesApi` オプションを `preloadCache` と同時に使用することで町丁目のキャッシュをローカルファイルから作成できます。この場合は `japaneseAddressesApi` に対して API の zip ファイルのパスを `file://` 形式の URL で指定してください。 + +```shell +# Geolonia 住所データのダウンロード +$ curl -sL https://github.com/geolonia/japanese-addresses/archive/refs/heads/master.zip > /path/to/japanese-addresses-master.zip +``` + +```javascript +// preloadCache オプションの使用例 +const { config, normalize } = require('@geolonia/normalize-japanese-addresses') +config.preloadCache = true +config.japaneseAddressesApi = 'file://path/to/japanese-addresses-master.zip' + +(function(){ + for (address of addresses) { + await normalize(address) + } +})() +``` + + + ## 正規化の内容 * `XXX郡` などの郡の名前が省略されている住所に対しては、それを補完します。 @@ -113,4 +149,4 @@ $ node sample.js - ソースコードのライセンスは MIT ライセンスです。 - ご利用に際しましては、できればソーシャルでのシェア、[Geolonia](https://geolonia.com/) へのリンクの設置などをしていただけると、開発者たちのモチベーションが上がると思います。 -プルリクや Issue は大歓迎です。住所の正規化を工夫すれば精度があがりそうなので、そのあたりのアイディアを募集しています。 +住所の正規化を工夫すれば精度があがりそうなので、そのあたりのアイディアを募集しています。 diff --git a/package.json b/package.json index 7769f83929..13e0a215ce 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "test": "npm run test:main && npm run test:addresses && npm run test:preload", "test:main": "jest test/main.test.ts", "test:addresses": "jest test/addresses.test.ts", - "test:preload": "jest test/preload.test.ts", + "test:preload": "curl -sL https://github.com/geolonia/japanese-addresses/archive/refs/heads/master.zip > ./test/japanese-addresses-master.zip && jest test/preload.test.ts", "test:generate-test-data": "npx ts-node -O '{\"module\":\"commonjs\"}' test/build-test-data.ts > test/addresses.csv", "lint": "eslint \"src/**/*.ts\" --fix", "build": "rm -rf ./dist && rollup -c ./rollup.config.ts" diff --git a/src/lib/cacheRegexes.ts b/src/lib/cacheRegexes.ts index ac6c71db4e..da0bf18c0e 100644 --- a/src/lib/cacheRegexes.ts +++ b/src/lib/cacheRegexes.ts @@ -42,6 +42,10 @@ export const getPrefectures = async (preloader?: () => Promise) => { const resp = await unfetch(`${currentConfig.japaneseAddressesApi}.json`) const data = (await resp.json()) as PrefectureList + return cachePrefectures(data) +} + +export const cachePrefectures = (data: PrefectureList) => { return (cachedPrefectures = data) } diff --git a/src/main-node.ts b/src/main-node.ts index 11d5ab8119..ac32cce1c2 100644 --- a/src/main-node.ts +++ b/src/main-node.ts @@ -1,5 +1,6 @@ import unfetch from 'isomorphic-unfetch' import { + cachePrefectures, cachedTownRegexes, getTownRegexPatterns, TownList, @@ -28,7 +29,9 @@ export const preload = async () => { // file:// でローカルにダウンロードした zip ファイルを参照する。 // https://github.com/geolonia/japanese-addresses のリポジトリと同じ構造を持つものを想定 if (currentConfig.japaneseAddressesApi.startsWith('file://')) { - zipBuffer = fs.readFileSync(currentConfig.japaneseAddressesApi) + zipBuffer = fs.readFileSync( + currentConfig.japaneseAddressesApi.replace(/^file:\//, ''), + ) } else { const resp = await unfetch( 'https://github.com/geolonia/japanese-addresses/archive/refs/heads/master.zip', @@ -50,6 +53,12 @@ export const preload = async () => { const townBuffer = await file.buffer() const towns = JSON.parse(townBuffer.toString('utf-8')) as TownList await getTownRegexPatterns(pref, city, towns) // call and set cache + } else if ( + file.type === 'File' && + file.path.match(/^(.+)\/api\/ja\.json$/) + ) { + const prefecturesBuffer = await file.buffer() + cachePrefectures(JSON.parse(prefecturesBuffer.toString('utf-8'))) } } @@ -57,6 +66,5 @@ export const preload = async () => { } export const config = currentConfig -export const normalize: Normalize.Normalizer = Normalize.createNormalizer( - preload, -) +export const normalize: Normalize.Normalizer = + Normalize.createNormalizer(preload) diff --git a/test/preload.test.ts b/test/preload.test.ts index fcc42271ff..760524f831 100644 --- a/test/preload.test.ts +++ b/test/preload.test.ts @@ -1,23 +1,29 @@ -import { normalize, preload } from '../src/main-node' +import { normalize, config, preload } from '../src/main-node' import { cachedTownRegexes } from '../src/lib/cacheRegexes' - +import path from 'path' import { performance } from 'perf_hooks' +import unfetch from 'isomorphic-unfetch' +jest.mock('isomorphic-unfetch') // disable request for testing jest.setTimeout(3 * 60 * 1000) beforeAll(async () => { + config.preloadCache = true + config.japaneseAddressesApi = + 'file:/' + path.resolve(__dirname, 'japanese-addresses-master.zip') console.time('preload') await preload() console.timeEnd('preload') + jest.setTimeout(5000) }) test('should preload cache', () => { expect(cachedTownRegexes.length).toBeGreaterThan(1800) -}, 5000) +}) -test('normalize should take less than 200ms to complete', async () => { +test('normalize should complete in the local environment', async () => { const started = performance.now() await normalize('京都府京田辺市同志社山手4丁目1-43') const finished = performance.now() - console.log(finished - started) - expect(finished - started).toBeLessThan(200) -}, 5000) + console.log('performance(ms): ', finished - started) + expect(unfetch).not.toBeCalled() +})