@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/lib/address/point/interpolation.ts +45 -39
- package/lib/address/point/schema.ts +17 -40
- package/lib/address/point.ts +316 -0
- package/lib/{address/index.ts → address.ts} +1 -1
- package/lib/ancestry/backfill.ts +20 -86
- package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
- package/lib/build/candidate.ts +122 -174
- package/lib/build/population-corrections.ts +64 -0
- package/lib/build/slim.ts +44 -114
- package/lib/candidate/alias-bags.ts +16 -17
- package/lib/candidate/ancestors/schema.ts +77 -61
- package/lib/candidate/ancestors/sidecar.ts +15 -22
- package/lib/candidate/country-display-names.ts +6 -20
- package/lib/candidate/extract-fold.ts +10 -55
- package/lib/candidate/fts.ts +5 -23
- package/lib/candidate/importance.ts +65 -68
- package/lib/candidate/lookup.ts +124 -415
- package/lib/candidate/name-roles.ts +15 -33
- package/lib/candidate/own-name.ts +35 -32
- package/lib/candidate/place-attrs.ts +20 -13
- package/lib/candidate/schema.ts +29 -65
- package/lib/candidate/scoring.ts +54 -93
- package/lib/capital-schema.ts +21 -17
- package/lib/capitals.ts +29 -27
- package/lib/coincident-roles.ts +85 -55
- package/lib/convention/schema.ts +15 -16
- package/lib/convention.ts +144 -0
- package/lib/coverage-manifest-schema.ts +40 -45
- package/lib/currency-backfill.ts +34 -79
- package/lib/env.ts +1 -1
- package/lib/exact-match.ts +32 -21
- package/lib/extracts.ts +97 -74
- package/lib/fst/autocomplete.ts +54 -37
- package/lib/fst/builder.ts +37 -41
- package/lib/fst/deserialize-web.ts +16 -17
- package/lib/fst/format.ts +41 -23
- package/lib/fst/freshness.ts +43 -120
- package/lib/fst/matcher.ts +7 -5
- package/lib/fst/serialize.ts +54 -74
- package/lib/fst/types.ts +78 -75
- package/lib/{fst/index.ts → fst.ts} +1 -0
- package/lib/fts/query.ts +5 -36
- package/lib/fts.ts +280 -0
- package/lib/geonames/aliases.ts +73 -144
- package/lib/geonames/postal.ts +162 -71
- package/lib/index.ts +9 -8
- package/lib/interpolation.ts +48 -100
- package/lib/lookup.ts +155 -270
- package/lib/name-score.ts +9 -7
- package/lib/nsul/lookup.ts +37 -54
- package/lib/nsul/schema.ts +16 -43
- package/lib/paths.ts +159 -0
- package/lib/place-importance-schema.ts +62 -169
- package/lib/poi/lookup.ts +104 -121
- package/lib/poi/schema.ts +42 -26
- package/lib/polygon-schema.ts +10 -6
- package/lib/postal/city/alias/lookup.ts +22 -40
- package/lib/postal/city/alias/schema.ts +14 -10
- package/lib/postal/city/candidate-schema.ts +26 -20
- package/lib/postcode-point-lookup.ts +8 -27
- package/lib/primary-preference.ts +46 -126
- package/lib/proximity-rerank.ts +44 -33
- package/lib/ranking-weights.ts +105 -78
- package/lib/region-keys.ts +70 -42
- package/lib/reverse.ts +149 -86
- package/lib/schema.ts +73 -50
- package/lib/search-fetch.ts +90 -68
- package/lib/sqlite/convention-source.ts +15 -23
- package/lib/sqlite/utils.ts +19 -22
- package/lib/street/centroid/schema.ts +37 -42
- package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
- package/lib/street/morphology/fst/builder.ts +60 -42
- package/lib/street/morphology/fst/loader.ts +40 -32
- package/lib/street/name-lookup.ts +45 -41
- package/lib/street/normalize.ts +88 -219
- package/lib/street/segment-schema.ts +116 -43
- package/lib/{street/index.ts → street.ts} +1 -1
- package/lib/types.ts +109 -150
- package/lib/unified-schema.ts +29 -29
- package/lib/uprn/existence.ts +30 -19
- package/lib/uprn/lookup.ts +29 -68
- package/lib/uprn/schema.ts +18 -40
- package/lib/weights-overlay-linker.ts +236 -252
- package/out/address/point/interpolation.d.ts +20 -23
- package/out/address/point/interpolation.d.ts.map +1 -1
- package/out/address/point/interpolation.js +42 -39
- package/out/address/point/interpolation.js.map +1 -1
- package/out/address/point/schema.d.ts +12 -35
- package/out/address/point/schema.d.ts.map +1 -1
- package/out/address/point/schema.js +3 -19
- package/out/address/point/schema.js.map +1 -1
- package/out/address/point.d.ts +57 -0
- package/out/address/point.d.ts.map +1 -0
- package/out/address/point.js +206 -0
- package/out/address/point.js.map +1 -0
- package/out/{address/index.js → address.d.ts} +2 -2
- package/out/address.d.ts.map +1 -0
- package/out/{address/index.d.ts → address.js} +2 -2
- package/out/address.js.map +1 -0
- package/out/ancestry/backfill.d.ts +11 -64
- package/out/ancestry/backfill.d.ts.map +1 -1
- package/out/ancestry/backfill.js +14 -74
- package/out/ancestry/backfill.js.map +1 -1
- package/out/ancestry.d.ts +49 -0
- package/out/ancestry.d.ts.map +1 -0
- package/out/ancestry.js +59 -0
- package/out/ancestry.js.map +1 -0
- package/out/build/candidate.d.ts +82 -112
- package/out/build/candidate.d.ts.map +1 -1
- package/out/build/candidate.js +17 -100
- package/out/build/candidate.js.map +1 -1
- package/out/build/population-corrections.d.ts +52 -0
- package/out/build/population-corrections.d.ts.map +1 -0
- package/out/build/population-corrections.js +40 -0
- package/out/build/population-corrections.js.map +1 -0
- package/out/build/slim.d.ts +8 -44
- package/out/build/slim.d.ts.map +1 -1
- package/out/build/slim.js +33 -94
- package/out/build/slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +6 -6
- package/out/candidate/alias-bags.d.ts.map +1 -1
- package/out/candidate/alias-bags.js +16 -17
- package/out/candidate/alias-bags.js.map +1 -1
- package/out/candidate/ancestors/schema.d.ts +73 -57
- package/out/candidate/ancestors/schema.d.ts.map +1 -1
- package/out/candidate/ancestors/schema.js +56 -48
- package/out/candidate/ancestors/schema.js.map +1 -1
- package/out/candidate/ancestors/sidecar.d.ts +3 -8
- package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
- package/out/candidate/ancestors/sidecar.js +15 -22
- package/out/candidate/ancestors/sidecar.js.map +1 -1
- package/out/candidate/country-display-names.d.ts +5 -15
- package/out/candidate/country-display-names.d.ts.map +1 -1
- package/out/candidate/country-display-names.js +6 -20
- package/out/candidate/country-display-names.js.map +1 -1
- package/out/candidate/extract-fold.d.ts +7 -15
- package/out/candidate/extract-fold.d.ts.map +1 -1
- package/out/candidate/extract-fold.js +5 -47
- package/out/candidate/extract-fold.js.map +1 -1
- package/out/candidate/fts.d.ts +5 -23
- package/out/candidate/fts.d.ts.map +1 -1
- package/out/candidate/fts.js +5 -23
- package/out/candidate/fts.js.map +1 -1
- package/out/candidate/importance.d.ts +60 -65
- package/out/candidate/importance.d.ts.map +1 -1
- package/out/candidate/importance.js +56 -63
- package/out/candidate/importance.js.map +1 -1
- package/out/candidate/lookup.d.ts +18 -55
- package/out/candidate/lookup.d.ts.map +1 -1
- package/out/candidate/lookup.js +82 -385
- package/out/candidate/lookup.js.map +1 -1
- package/out/candidate/name-roles.d.ts +9 -21
- package/out/candidate/name-roles.d.ts.map +1 -1
- package/out/candidate/name-roles.js +15 -33
- package/out/candidate/name-roles.js.map +1 -1
- package/out/candidate/own-name.d.ts +23 -25
- package/out/candidate/own-name.d.ts.map +1 -1
- package/out/candidate/own-name.js +35 -32
- package/out/candidate/own-name.js.map +1 -1
- package/out/candidate/place-attrs.d.ts +20 -13
- package/out/candidate/place-attrs.d.ts.map +1 -1
- package/out/candidate/place-attrs.js +4 -5
- package/out/candidate/place-attrs.js.map +1 -1
- package/out/candidate/schema.d.ts +27 -62
- package/out/candidate/schema.d.ts.map +1 -1
- package/out/candidate/schema.js +10 -22
- package/out/candidate/schema.js.map +1 -1
- package/out/candidate/scoring.d.ts +7 -8
- package/out/candidate/scoring.d.ts.map +1 -1
- package/out/candidate/scoring.js +52 -89
- package/out/candidate/scoring.js.map +1 -1
- package/out/capital-schema.d.ts +21 -17
- package/out/capital-schema.d.ts.map +1 -1
- package/out/capital-schema.js +17 -15
- package/out/capital-schema.js.map +1 -1
- package/out/capitals.d.ts +27 -25
- package/out/capitals.d.ts.map +1 -1
- package/out/capitals.js +23 -21
- package/out/capitals.js.map +1 -1
- package/out/coincident-roles.d.ts +60 -43
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +72 -50
- package/out/coincident-roles.js.map +1 -1
- package/out/convention/schema.d.ts +14 -14
- package/out/convention/schema.d.ts.map +1 -1
- package/out/convention/schema.js +6 -4
- package/out/convention/schema.js.map +1 -1
- package/out/convention.d.ts +97 -0
- package/out/convention.d.ts.map +1 -0
- package/out/convention.js +81 -0
- package/out/convention.js.map +1 -0
- package/out/coverage-manifest-schema.d.ts +34 -39
- package/out/coverage-manifest-schema.d.ts.map +1 -1
- package/out/coverage-manifest-schema.js +25 -34
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +16 -38
- package/out/currency-backfill.d.ts.map +1 -1
- package/out/currency-backfill.js +19 -46
- package/out/currency-backfill.js.map +1 -1
- package/out/env.d.ts +1 -1
- package/out/env.js +1 -1
- package/out/exact-match.d.ts +19 -10
- package/out/exact-match.d.ts.map +1 -1
- package/out/exact-match.js +32 -21
- package/out/exact-match.js.map +1 -1
- package/out/extracts.d.ts +66 -55
- package/out/extracts.d.ts.map +1 -1
- package/out/extracts.js +63 -55
- package/out/extracts.js.map +1 -1
- package/out/fst/autocomplete.d.ts +29 -21
- package/out/fst/autocomplete.d.ts.map +1 -1
- package/out/fst/autocomplete.js +39 -28
- package/out/fst/autocomplete.js.map +1 -1
- package/out/fst/builder.d.ts.map +1 -1
- package/out/fst/builder.js +37 -41
- package/out/fst/builder.js.map +1 -1
- package/out/fst/deserialize-web.d.ts +4 -4
- package/out/fst/deserialize-web.d.ts.map +1 -1
- package/out/fst/deserialize-web.js +15 -16
- package/out/fst/deserialize-web.js.map +1 -1
- package/out/fst/format.d.ts +41 -23
- package/out/fst/format.d.ts.map +1 -1
- package/out/fst/format.js +41 -23
- package/out/fst/format.js.map +1 -1
- package/out/fst/freshness.d.ts +19 -81
- package/out/fst/freshness.d.ts.map +1 -1
- package/out/fst/freshness.js +31 -94
- package/out/fst/freshness.js.map +1 -1
- package/out/fst/matcher.d.ts +5 -4
- package/out/fst/matcher.d.ts.map +1 -1
- package/out/fst/matcher.js +2 -2
- package/out/fst/matcher.js.map +1 -1
- package/out/fst/serialize.d.ts +28 -28
- package/out/fst/serialize.d.ts.map +1 -1
- package/out/fst/serialize.js +53 -71
- package/out/fst/serialize.js.map +1 -1
- package/out/fst/types.d.ts +78 -74
- package/out/fst/types.d.ts.map +1 -1
- package/out/fst/types.js +1 -4
- package/out/fst/types.js.map +1 -1
- package/out/{fst/index.js → fst.d.ts} +2 -1
- package/out/fst.d.ts.map +1 -0
- package/out/{fst/index.d.ts → fst.js} +2 -1
- package/out/fst.js.map +1 -0
- package/out/fts/query.d.ts +2 -27
- package/out/fts/query.d.ts.map +1 -1
- package/out/fts/query.js +5 -36
- package/out/fts/query.js.map +1 -1
- package/out/fts.d.ts +126 -0
- package/out/fts.d.ts.map +1 -0
- package/out/fts.js +188 -0
- package/out/fts.js.map +1 -0
- package/out/geonames/aliases.d.ts +26 -62
- package/out/geonames/aliases.d.ts.map +1 -1
- package/out/geonames/aliases.js +45 -117
- package/out/geonames/aliases.js.map +1 -1
- package/out/geonames/postal.d.ts +84 -44
- package/out/geonames/postal.d.ts.map +1 -1
- package/out/geonames/postal.js +115 -73
- package/out/geonames/postal.js.map +1 -1
- package/out/{geonames/index.js → geonames.d.ts} +1 -1
- package/out/geonames.d.ts.map +1 -0
- package/out/{geonames/index.d.ts → geonames.js} +1 -1
- package/out/geonames.js.map +1 -0
- package/out/index.d.ts +9 -8
- package/out/index.d.ts.map +1 -1
- package/out/index.js +6 -5
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +18 -55
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +27 -69
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +23 -51
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +136 -234
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +2 -2
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js +9 -7
- package/out/name-score.js.map +1 -1
- package/out/nsul/lookup.d.ts +33 -34
- package/out/nsul/lookup.d.ts.map +1 -1
- package/out/nsul/lookup.js +26 -40
- package/out/nsul/lookup.js.map +1 -1
- package/out/nsul/schema.d.ts +16 -43
- package/out/nsul/schema.d.ts.map +1 -1
- package/out/nsul/schema.js +9 -35
- package/out/nsul/schema.js.map +1 -1
- package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
- package/out/nsul.d.ts.map +1 -0
- package/out/{nsul/index.js → nsul.js} +1 -1
- package/out/nsul.js.map +1 -0
- package/out/paths.d.ts +124 -0
- package/out/paths.d.ts.map +1 -0
- package/out/paths.js +104 -0
- package/out/paths.js.map +1 -0
- package/out/place-importance-schema.d.ts +51 -143
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +28 -143
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi/lookup.d.ts +40 -47
- package/out/poi/lookup.d.ts.map +1 -1
- package/out/poi/lookup.js +69 -96
- package/out/poi/lookup.js.map +1 -1
- package/out/poi/schema.d.ts +41 -25
- package/out/poi/schema.d.ts.map +1 -1
- package/out/poi/schema.js +25 -17
- package/out/poi/schema.js.map +1 -1
- package/out/{poi/index.js → poi.d.ts} +1 -1
- package/out/poi.d.ts.map +1 -0
- package/out/{poi/index.d.ts → poi.js} +1 -1
- package/out/poi.js.map +1 -0
- package/out/polygon-schema.d.ts +10 -6
- package/out/polygon-schema.d.ts.map +1 -1
- package/out/polygon-schema.js +2 -2
- package/out/polygon-schema.js.map +1 -1
- package/out/postal/city/alias/lookup.d.ts +20 -23
- package/out/postal/city/alias/lookup.d.ts.map +1 -1
- package/out/postal/city/alias/lookup.js +17 -30
- package/out/postal/city/alias/lookup.js.map +1 -1
- package/out/postal/city/alias/schema.d.ts +14 -10
- package/out/postal/city/alias/schema.d.ts.map +1 -1
- package/out/postal/city/alias/schema.js +10 -8
- package/out/postal/city/alias/schema.js.map +1 -1
- package/out/postal/city/candidate-schema.d.ts +25 -19
- package/out/postal/city/candidate-schema.d.ts.map +1 -1
- package/out/postal/city/candidate-schema.js +21 -17
- package/out/postal/city/candidate-schema.js.map +1 -1
- package/out/{postal/index.d.ts → postal.d.ts} +1 -1
- package/out/postal.d.ts.map +1 -0
- package/out/{postal/index.js → postal.js} +1 -1
- package/out/postal.js.map +1 -0
- package/out/postcode-point-lookup.d.ts +6 -24
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +5 -17
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/primary-preference.d.ts +38 -92
- package/out/primary-preference.d.ts.map +1 -1
- package/out/primary-preference.js +15 -99
- package/out/primary-preference.js.map +1 -1
- package/out/proximity-rerank.d.ts +41 -30
- package/out/proximity-rerank.d.ts.map +1 -1
- package/out/proximity-rerank.js +38 -29
- package/out/proximity-rerank.js.map +1 -1
- package/out/ranking-weights.d.ts +98 -64
- package/out/ranking-weights.d.ts.map +1 -1
- package/out/ranking-weights.js +26 -25
- package/out/ranking-weights.js.map +1 -1
- package/out/region-keys.d.ts +50 -31
- package/out/region-keys.d.ts.map +1 -1
- package/out/region-keys.js +68 -40
- package/out/region-keys.js.map +1 -1
- package/out/reverse.d.ts +78 -50
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +98 -61
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +72 -49
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js +4 -5
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +16 -12
- package/out/search-fetch.d.ts.map +1 -1
- package/out/search-fetch.js +83 -63
- package/out/search-fetch.js.map +1 -1
- package/out/sqlite/convention-source.d.ts +12 -16
- package/out/sqlite/convention-source.d.ts.map +1 -1
- package/out/sqlite/convention-source.js +13 -22
- package/out/sqlite/convention-source.js.map +1 -1
- package/out/sqlite/utils.d.ts +19 -19
- package/out/sqlite/utils.d.ts.map +1 -1
- package/out/sqlite/utils.js +14 -15
- package/out/sqlite/utils.js.map +1 -1
- package/out/street/centroid/schema.d.ts +37 -42
- package/out/street/centroid/schema.d.ts.map +1 -1
- package/out/street/centroid/schema.js +9 -21
- package/out/street/centroid/schema.js.map +1 -1
- package/out/street/centroid.d.ts +30 -0
- package/out/street/centroid.d.ts.map +1 -0
- package/out/street/{centroid/index.js → centroid.js} +13 -24
- package/out/street/centroid.js.map +1 -0
- package/out/street/morphology/fst/builder.d.ts +20 -10
- package/out/street/morphology/fst/builder.d.ts.map +1 -1
- package/out/street/morphology/fst/builder.js +44 -34
- package/out/street/morphology/fst/builder.js.map +1 -1
- package/out/street/morphology/fst/loader.d.ts +33 -26
- package/out/street/morphology/fst/loader.d.ts.map +1 -1
- package/out/street/morphology/fst/loader.js +23 -22
- package/out/street/morphology/fst/loader.js.map +1 -1
- package/out/street/name-lookup.d.ts +24 -18
- package/out/street/name-lookup.d.ts.map +1 -1
- package/out/street/name-lookup.js +34 -35
- package/out/street/name-lookup.js.map +1 -1
- package/out/street/normalize.d.ts +35 -136
- package/out/street/normalize.d.ts.map +1 -1
- package/out/street/normalize.js +77 -194
- package/out/street/normalize.js.map +1 -1
- package/out/street/segment-schema.d.ts +79 -39
- package/out/street/segment-schema.d.ts.map +1 -1
- package/out/street/segment-schema.js +71 -21
- package/out/street/segment-schema.js.map +1 -1
- package/out/{street/index.js → street.d.ts} +2 -2
- package/out/street.d.ts.map +1 -0
- package/out/{street/index.d.ts → street.js} +2 -2
- package/out/street.js.map +1 -0
- package/out/types.d.ts +84 -149
- package/out/types.d.ts.map +1 -1
- package/out/types.js +0 -6
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +8 -12
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +29 -29
- package/out/unified-schema.js.map +1 -1
- package/out/uprn/existence.d.ts +28 -17
- package/out/uprn/existence.d.ts.map +1 -1
- package/out/uprn/existence.js +26 -16
- package/out/uprn/existence.js.map +1 -1
- package/out/uprn/lookup.d.ts +14 -44
- package/out/uprn/lookup.d.ts.map +1 -1
- package/out/uprn/lookup.js +21 -57
- package/out/uprn/lookup.js.map +1 -1
- package/out/uprn/schema.d.ts +18 -40
- package/out/uprn/schema.d.ts.map +1 -1
- package/out/uprn/schema.js +10 -32
- package/out/uprn/schema.js.map +1 -1
- package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
- package/out/uprn.d.ts.map +1 -0
- package/out/{uprn/index.js → uprn.js} +1 -1
- package/out/uprn.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +138 -144
- package/out/weights-overlay-linker.d.ts.map +1 -1
- package/out/weights-overlay-linker.js +105 -159
- package/out/weights-overlay-linker.js.map +1 -1
- package/package.json +91 -596
- package/lib/address/point/index.ts +0 -328
- package/lib/convention/index.ts +0 -154
- package/lib/fts/index.ts +0 -361
- package/out/address/index.d.ts.map +0 -1
- package/out/address/index.js.map +0 -1
- package/out/address/point/index.d.ts +0 -53
- package/out/address/point/index.d.ts.map +0 -1
- package/out/address/point/index.js +0 -222
- package/out/address/point/index.js.map +0 -1
- package/out/ancestry/index.d.ts +0 -45
- package/out/ancestry/index.d.ts.map +0 -1
- package/out/ancestry/index.js +0 -55
- package/out/ancestry/index.js.map +0 -1
- package/out/convention/index.d.ts +0 -106
- package/out/convention/index.d.ts.map +0 -1
- package/out/convention/index.js +0 -93
- package/out/convention/index.js.map +0 -1
- package/out/fst/index.d.ts.map +0 -1
- package/out/fst/index.js.map +0 -1
- package/out/fts/index.d.ts +0 -184
- package/out/fts/index.d.ts.map +0 -1
- package/out/fts/index.js +0 -277
- package/out/fts/index.js.map +0 -1
- package/out/geonames/index.d.ts.map +0 -1
- package/out/geonames/index.js.map +0 -1
- package/out/nsul/index.d.ts.map +0 -1
- package/out/nsul/index.js.map +0 -1
- package/out/poi/index.d.ts.map +0 -1
- package/out/poi/index.js.map +0 -1
- package/out/postal/index.d.ts.map +0 -1
- package/out/postal/index.js.map +0 -1
- package/out/street/centroid/index.d.ts +0 -40
- package/out/street/centroid/index.d.ts.map +0 -1
- package/out/street/centroid/index.js.map +0 -1
- package/out/street/index.d.ts.map +0 -1
- package/out/street/index.js.map +0 -1
- package/out/uprn/index.d.ts.map +0 -1
- package/out/uprn/index.js.map +0 -1
- /package/lib/{geonames/index.ts → geonames.ts} +0 -0
- /package/lib/{nsul/index.ts → nsul.ts} +0 -0
- /package/lib/{poi/index.ts → poi.ts} +0 -0
- /package/lib/{postal/index.ts → postal.ts} +0 -0
- /package/lib/{uprn/index.ts → uprn.ts} +0 -0
package/out/fts.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
import { tableExists } from "@mailwoman/sqlite/introspection";
|
|
7
|
+
/**
|
|
8
|
+
* The name of the FTS5 virtual table that indexes WOF place names for `match` queries.
|
|
9
|
+
*/
|
|
10
|
+
export const PLACE_SEARCH_TABLE = "place_search";
|
|
11
|
+
/**
|
|
12
|
+
* The separator between aliases in the `alt_names` bag.
|
|
13
|
+
* It stops a phrase query from matching across two aliases.
|
|
14
|
+
*
|
|
15
|
+
* FTS5 assigns positions only to tokens.
|
|
16
|
+
* Spaces and punctuation are not tokens and would leave the aliases adjacent,
|
|
17
|
+
* but unicode61 indexes the Private Use Area codepoint U+E000 as a token.
|
|
18
|
+
*
|
|
19
|
+
* Query sanitizers strip this character, so no user query can match the separator.
|
|
20
|
+
*/
|
|
21
|
+
export const ALIAS_SEPARATOR = "\uE000";
|
|
22
|
+
const ALIAS_SEPARATOR_CODEPOINT = ALIAS_SEPARATOR.codePointAt(0);
|
|
23
|
+
/**
|
|
24
|
+
* Folds a query or name for exact-tier comparison by lowercasing, trimming
|
|
25
|
+
* and collapsing internal whitespace.
|
|
26
|
+
*
|
|
27
|
+
* Every exact-tier consumer uses this function, so its output compares equal to
|
|
28
|
+
* the aliases that {@link aliasBagExactMatch} parses.
|
|
29
|
+
*/
|
|
30
|
+
export function foldQueryText(input) {
|
|
31
|
+
return input.toLowerCase().trim().replaceAll(/\s+/g, " ");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns whether any alias in an `alt_names` bag exactly equals the folded query.
|
|
35
|
+
*
|
|
36
|
+
* A bag without {@link ALIAS_SEPARATOR} is a legacy space-joined bag without alias boundaries.
|
|
37
|
+
* For such a bag, the function checks word-bounded containment only when no candidate matched strictly.
|
|
38
|
+
*
|
|
39
|
+
* Containment by itself would promote fragments such as "York" inside "New York City".
|
|
40
|
+
*
|
|
41
|
+
* @param altNames The `alt_names` bag from `place_search`, or null when the row has no aliases.
|
|
42
|
+
* @param normalizedQuery The query folded by {@link foldQueryText}.
|
|
43
|
+
* @param anyStrictExact Whether any candidate already matched on its canonical name or region abbreviation.
|
|
44
|
+
* Only legacy bags use it.
|
|
45
|
+
*/
|
|
46
|
+
export function aliasBagExactMatch(altNames, normalizedQuery, anyStrictExact) {
|
|
47
|
+
if (!altNames || altNames === "" || !normalizedQuery)
|
|
48
|
+
return false;
|
|
49
|
+
if (altNames.includes(ALIAS_SEPARATOR)) {
|
|
50
|
+
return altNames.split(ALIAS_SEPARATOR).some((alias) => foldQueryText(alias) === normalizedQuery);
|
|
51
|
+
}
|
|
52
|
+
if (anyStrictExact)
|
|
53
|
+
return false;
|
|
54
|
+
return ` ${foldQueryText(altNames)} `.includes(` ${normalizedQuery} `);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The name of the R*Tree virtual table that indexes WOF place bounding boxes for bbox and proximity lookups.
|
|
58
|
+
*/
|
|
59
|
+
export const PLACE_BBOX_TABLE = "place_bbox";
|
|
60
|
+
/**
|
|
61
|
+
* The name of the sparse table that stores `wof:population` per place.
|
|
62
|
+
*
|
|
63
|
+
* The lookup uses this value to apply the population ranking boost.
|
|
64
|
+
*
|
|
65
|
+
* A place without a row gets no boost and no penalty.
|
|
66
|
+
*/
|
|
67
|
+
export const PLACE_POPULATION_TABLE = "place_population";
|
|
68
|
+
/**
|
|
69
|
+
* The name of the table of per-place `referential` and `encyclopedic` scores,
|
|
70
|
+
* built by `mailwoman gazetteer importance`.
|
|
71
|
+
*
|
|
72
|
+
* The lookup copies `encyclopedic` onto results without ranking by it.
|
|
73
|
+
* It refuses to read an older table with a single `importance` column.
|
|
74
|
+
*/
|
|
75
|
+
export const PLACE_IMPORTANCE_TABLE = "place_importance";
|
|
76
|
+
/**
|
|
77
|
+
* Builds the `place_search` FTS5 table and the `place_bbox` R*Tree from a WOF
|
|
78
|
+
* database's `spr` and `names` tables.
|
|
79
|
+
*
|
|
80
|
+
* Without `drop: true`, an existing index is kept.
|
|
81
|
+
*/
|
|
82
|
+
export function buildPlaceSearchFTS(db, opts = {}) {
|
|
83
|
+
const start = Date.now();
|
|
84
|
+
const onProgress = opts.onProgress ?? (() => { });
|
|
85
|
+
onProgress("checking");
|
|
86
|
+
const ftsExisting = tableExists(db, PLACE_SEARCH_TABLE);
|
|
87
|
+
const bboxExisting = tableExists(db, PLACE_BBOX_TABLE);
|
|
88
|
+
let ftsCreated = false;
|
|
89
|
+
if (ftsExisting && opts.drop) {
|
|
90
|
+
onProgress("dropping", PLACE_SEARCH_TABLE);
|
|
91
|
+
db.exec(`DROP TABLE ${PLACE_SEARCH_TABLE}`);
|
|
92
|
+
}
|
|
93
|
+
if (!ftsExisting || opts.drop) {
|
|
94
|
+
onProgress("creating");
|
|
95
|
+
db.exec(`
|
|
96
|
+
CREATE VIRTUAL TABLE ${PLACE_SEARCH_TABLE} USING fts5(
|
|
97
|
+
wof_id UNINDEXED,
|
|
98
|
+
name,
|
|
99
|
+
alt_names,
|
|
100
|
+
tokenize = 'unicode61 remove_diacritics 2'
|
|
101
|
+
);
|
|
102
|
+
`);
|
|
103
|
+
onProgress("populating");
|
|
104
|
+
db.exec(`
|
|
105
|
+
INSERT INTO ${PLACE_SEARCH_TABLE} (wof_id, name, alt_names)
|
|
106
|
+
SELECT
|
|
107
|
+
spr.id,
|
|
108
|
+
spr.name,
|
|
109
|
+
COALESCE((
|
|
110
|
+
SELECT GROUP_CONCAT(
|
|
111
|
+
REPLACE(name, char(${ALIAS_SEPARATOR_CODEPOINT}), ' '),
|
|
112
|
+
' ' || char(${ALIAS_SEPARATOR_CODEPOINT}) || ' '
|
|
113
|
+
) || ' ' || char(${ALIAS_SEPARATOR_CODEPOINT})
|
|
114
|
+
FROM names WHERE names.id = spr.id
|
|
115
|
+
), '')
|
|
116
|
+
FROM spr
|
|
117
|
+
WHERE spr.is_current != 0
|
|
118
|
+
AND spr.is_deprecated = 0
|
|
119
|
+
AND spr.name IS NOT NULL;
|
|
120
|
+
`);
|
|
121
|
+
ftsCreated = true;
|
|
122
|
+
}
|
|
123
|
+
const ftsCountRow = db.prepare(`SELECT COUNT(*) AS n FROM ${PLACE_SEARCH_TABLE}`).get();
|
|
124
|
+
let bboxCreated = false;
|
|
125
|
+
if (bboxExisting && opts.drop) {
|
|
126
|
+
onProgress("dropping", PLACE_BBOX_TABLE);
|
|
127
|
+
db.exec(`DROP TABLE ${PLACE_BBOX_TABLE}`);
|
|
128
|
+
}
|
|
129
|
+
if (!bboxExisting || opts.drop) {
|
|
130
|
+
onProgress("creating-bbox");
|
|
131
|
+
db.exec(`
|
|
132
|
+
CREATE VIRTUAL TABLE ${PLACE_BBOX_TABLE} USING rtree(
|
|
133
|
+
id,
|
|
134
|
+
min_lat, max_lat,
|
|
135
|
+
min_lon, max_lon
|
|
136
|
+
);
|
|
137
|
+
`);
|
|
138
|
+
onProgress("populating-bbox");
|
|
139
|
+
db.exec(`
|
|
140
|
+
INSERT INTO ${PLACE_BBOX_TABLE} (id, min_lat, max_lat, min_lon, max_lon)
|
|
141
|
+
SELECT
|
|
142
|
+
spr.id,
|
|
143
|
+
spr.min_latitude,
|
|
144
|
+
spr.max_latitude,
|
|
145
|
+
spr.min_longitude,
|
|
146
|
+
spr.max_longitude
|
|
147
|
+
FROM spr
|
|
148
|
+
WHERE spr.is_current != 0
|
|
149
|
+
AND spr.is_deprecated = 0
|
|
150
|
+
AND spr.min_latitude IS NOT NULL
|
|
151
|
+
AND spr.max_latitude IS NOT NULL
|
|
152
|
+
AND spr.min_longitude IS NOT NULL
|
|
153
|
+
AND spr.max_longitude IS NOT NULL
|
|
154
|
+
AND NOT (spr.min_latitude = 0 AND spr.max_latitude = 0
|
|
155
|
+
AND spr.min_longitude = 0 AND spr.max_longitude = 0);
|
|
156
|
+
`);
|
|
157
|
+
bboxCreated = true;
|
|
158
|
+
}
|
|
159
|
+
const bboxCountRow = db.prepare(`SELECT COUNT(*) AS n FROM ${PLACE_BBOX_TABLE}`).get();
|
|
160
|
+
onProgress("done", `${ftsCountRow.n} FTS rows + ${bboxCountRow.n} bbox rows ` +
|
|
161
|
+
`(${ftsCreated ? "built" : "preexisting"} / ${bboxCreated ? "built" : "preexisting"})`);
|
|
162
|
+
return {
|
|
163
|
+
created: ftsCreated,
|
|
164
|
+
indexedRows: ftsCountRow.n,
|
|
165
|
+
bboxCreated,
|
|
166
|
+
bboxIndexedRows: bboxCountRow.n,
|
|
167
|
+
durationMs: Date.now() - start,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Returns whether the connected database has the `place_search` FTS table.
|
|
172
|
+
*/
|
|
173
|
+
export function placeSearchFTSExists(db) {
|
|
174
|
+
return tableExists(db, PLACE_SEARCH_TABLE);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Returns whether the connected database has the `place_bbox` R*Tree table.
|
|
178
|
+
*/
|
|
179
|
+
export function placeBboxExists(db) {
|
|
180
|
+
return tableExists(db, PLACE_BBOX_TABLE);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Returns whether the connected database has the `place_population` table.
|
|
184
|
+
*/
|
|
185
|
+
export function placePopulationExists(db) {
|
|
186
|
+
return tableExists(db, PLACE_POPULATION_TABLE);
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=fts.js.map
|
package/out/fts.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fts.js","sourceRoot":"","sources":["../lib/fts.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,94 +2,58 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* #743/#193 — fold GeoNames bilingual / alt-language place-names into a WOF/unified admin DB as
|
|
7
|
-
* first-class places. The hard-filter recall gap on bilingual countries (the address says
|
|
8
|
-
* "Karjaa" but the table holds the Swedish "Karis") is missing alt-LANGUAGE names, not missing
|
|
9
|
-
* places: the WOF/Overture `names` carried only the primary, so the candidate build's Latin-alias
|
|
10
|
-
* explode (build-candidate pass 2) had nothing to widen. GeoNames' per-country dump carries the
|
|
11
|
-
* variants inline (the Karis row's `alternatenames` includes "Karjaa").
|
|
12
|
-
*
|
|
13
|
-
* For each POPULATED place (feature class `P`) this writes an `spr` row + `names` rows (primary +
|
|
14
|
-
* Latin alt-names) + population into the SAME tables the WOF/Overture paths use — synthetic ids
|
|
15
|
-
* based at {@link GEONAMES_ID_BASE} so the three sources never collide. The caller then rebuilds
|
|
16
|
-
* `place_search` ({@link buildPlaceSearchFTS} with `drop: true`) so the candidate build carries
|
|
17
|
-
* Karjaa↔Karis. Proven (FI hard-resolve 69.5 → 85.8 %, coverage 74.4 → 94.0 %); duplicating a
|
|
18
|
-
* place already held under another source is benign — the rows share name_key+coord and the
|
|
19
|
-
* candidate ranking dedupes by score.
|
|
20
|
-
*
|
|
21
|
-
* This is the package home so the canonical `build-unified-wof --geonames-countries`, the
|
|
22
|
-
* pipeline fold (`gazetteer-pipeline/admin/fold-geonames`), AND the `mailwoman gazetteer` commands all share
|
|
23
|
-
* ONE implementation. GeoNames dump = `download.geonames.org/export/dump/<CC>.zip` → `<CC>.txt`
|
|
24
|
-
* (TSV).
|
|
25
5
|
*/
|
|
26
6
|
import type { DatabaseClient } from "@mailwoman/sqlite/client";
|
|
27
7
|
import { type PathBuilderLike } from "path-ts";
|
|
28
8
|
import type { WOFDatabase } from "#schema";
|
|
29
9
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* — so a fold's output is a function of its country list and dumps ALONE, never of what the DB happened to hold first.
|
|
33
|
-
* Returns the rows removed per table.
|
|
34
|
-
*
|
|
35
|
-
* This exists because the synthetic id is a POSITION (`GEONAMES_ID_BASE + n`, counted across the country list in
|
|
36
|
-
* order), not a derivation from the geonameid: change the list, its order, or a dump's contents and every subsequent id
|
|
37
|
-
* shifts. Without the purge, a second fold overwrote the `spr` PREFIX it reached (`INSERT OR REPLACE`) while its
|
|
38
|
-
* `names`/`ancestors` rows merely appended (bare `INSERT`) and `place_population` skipped unpopulated places entirely —
|
|
39
|
-
* so the previous run's names, ancestry and populations stayed bound to ids now describing other places.
|
|
10
|
+
* Deletes every row the GeoNames alias fold owns, with ids in
|
|
11
|
+
* `[GEONAMES_ID_BASE, GEONAMES_POSTAL_ID_BASE)`, and returns the count removed per table.
|
|
40
12
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* population landed on a Lithuanian hamlet.
|
|
45
|
-
*
|
|
46
|
-
* The upper bound is NOT the end of the id space. Each later extract owns a range above this one — GeoNames-postal @
|
|
47
|
-
* 9.5e12, NL-PC6 @ 9.6e12, Code-Point @ 9.7e12, NI @ 9.8e12 — and a purge that ran past {@link GEONAMES_POSTAL_ID_BASE}
|
|
48
|
-
* would delete them.
|
|
13
|
+
* Fold ids are assigned sequentially, so a re-fold without this purge would attach
|
|
14
|
+
* stale names, ancestors and populations to other places.
|
|
15
|
+
* The upper bound leaves the postal and postcode id ranges above it untouched.
|
|
49
16
|
*/
|
|
50
17
|
export declare function purgeGeonamesAliasRange<DB>(db: DatabaseClient<DB>): Record<string, number>;
|
|
51
18
|
/**
|
|
52
|
-
*
|
|
19
|
+
* One progress event per country dump that the ingest processed or skipped.
|
|
53
20
|
*/
|
|
54
21
|
export interface GeonamesIngestProgress {
|
|
55
22
|
/**
|
|
56
|
-
* ISO 3166-1 alpha-2 code.
|
|
23
|
+
* The ISO 3166-1 alpha-2 country code.
|
|
57
24
|
*/
|
|
58
25
|
country: string;
|
|
59
26
|
/**
|
|
60
|
-
*
|
|
27
|
+
* The number of populated places ingested from this country's dump, or 0 when it was skipped.
|
|
61
28
|
*/
|
|
62
29
|
places: number;
|
|
63
30
|
/**
|
|
64
|
-
*
|
|
31
|
+
* Whether the country's `<CC>.txt` dump was missing.
|
|
32
|
+
*
|
|
33
|
+
* A missing dump skips the country without failing the ingest.
|
|
65
34
|
*/
|
|
66
35
|
skipped: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The number of alternate names that the alias filter rejected.
|
|
38
|
+
*
|
|
39
|
+
* It distinguishes a sparse source from aliases that the fold discarded.
|
|
40
|
+
*/
|
|
41
|
+
aliasesRefused: number | null;
|
|
67
42
|
}
|
|
68
43
|
/**
|
|
69
|
-
*
|
|
70
|
-
|
|
44
|
+
* Formats a GeoNames fold progress event as one log line.
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatGeonamesIngestProgress(event: GeonamesIngestProgress, missingFile?: PathBuilderLike): string;
|
|
47
|
+
/**
|
|
48
|
+
* Purges the fold's id range, then adds GeoNames `P`-class places and their
|
|
49
|
+
* alternate names for `countries` to `db`.
|
|
50
|
+
* It returns the number of places ingested.
|
|
71
51
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* the candidate build's alias pass.
|
|
52
|
+
* The caller must then rebuild `place_search` with `buildPlaceSearchFTS(db, { drop: true })`
|
|
53
|
+
* to make the new names searchable.
|
|
75
54
|
*/
|
|
76
55
|
export declare function ingestGeonamesAliases(db: DatabaseClient<WOFDatabase>, countries: string[], geonamesDir: PathBuilderLike, onProgress?: (event: GeonamesIngestProgress) => void, opts?: {
|
|
77
|
-
/**
|
|
78
|
-
* #267: the countries for which to ALSO fold the GeoNames A-class admin (PCLI country + ADM1 regions) and link each
|
|
79
|
-
* locality's `parent_id` + ancestry chain (locality → region → country). PER-COUNTRY because a country that already
|
|
80
|
-
* carries WOF admin would double up — pass only the ZERO-COVERAGE gap countries (the coverage-expansion targets),
|
|
81
|
-
* never the EU alias set. Without admin, a gap country's localities are orphans (`parent_id=-1`, no ancestors), so
|
|
82
|
-
* `parentID` scoping and adminCoherence can't reach them and "Tbilisi, GE" can't resolve.
|
|
83
|
-
*/
|
|
84
56
|
adminForCountries?: ReadonlySet<string>;
|
|
85
|
-
/**
|
|
86
|
-
* #936: directory of per-country alternateNamesV2 dumps
|
|
87
|
-
* (`download.geonames.org/export/dump/alternatenames/<CC>.zip` → `<CC>.txt`). When a country's file is present,
|
|
88
|
-
* alias rows gain their language tag, `privateuse` ("preferred" from `isPreferredName`), and the `official` bit
|
|
89
|
-
* (language is CLDR-official for the country, colloquial/historic excluded — the rule the #936 risk probe measured
|
|
90
|
-
* at 7 new name-exact collisions globally). The main dump's bare `alternatenames` list still decides WHICH rows
|
|
91
|
-
* exist; V2 only decorates them. Missing file = the pre-#936 untagged behavior, not an error.
|
|
92
|
-
*/
|
|
93
57
|
alternateDir?: PathBuilderLike;
|
|
94
58
|
}): Promise<number>;
|
|
95
59
|
//# sourceMappingURL=aliases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../../lib/geonames/aliases.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../../lib/geonames/aliases.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,SAAS,CAAA;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAY1F;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAA;IAEhB;;;;OAIG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,sBAAsB,EAAE,WAAW,CAAC,EAAE,eAAe,GAAG,MAAM,CAMjH;AAgED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAC1C,EAAE,EAAE,cAAc,CAAC,WAAW,CAAC,EAC/B,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,eAAe,EAC5B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,EACpD,IAAI,CAAC,EAAE;IACN,iBAAiB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAEvC,YAAY,CAAC,EAAE,eAAe,CAAA;CAC9B,GACC,OAAO,CAAC,MAAM,CAAC,CAyLjB"}
|
package/out/geonames/aliases.js
CHANGED
|
@@ -2,57 +2,20 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* #743/#193 — fold GeoNames bilingual / alt-language place-names into a WOF/unified admin DB as
|
|
7
|
-
* first-class places. The hard-filter recall gap on bilingual countries (the address says
|
|
8
|
-
* "Karjaa" but the table holds the Swedish "Karis") is missing alt-LANGUAGE names, not missing
|
|
9
|
-
* places: the WOF/Overture `names` carried only the primary, so the candidate build's Latin-alias
|
|
10
|
-
* explode (build-candidate pass 2) had nothing to widen. GeoNames' per-country dump carries the
|
|
11
|
-
* variants inline (the Karis row's `alternatenames` includes "Karjaa").
|
|
12
|
-
*
|
|
13
|
-
* For each POPULATED place (feature class `P`) this writes an `spr` row + `names` rows (primary +
|
|
14
|
-
* Latin alt-names) + population into the SAME tables the WOF/Overture paths use — synthetic ids
|
|
15
|
-
* based at {@link GEONAMES_ID_BASE} so the three sources never collide. The caller then rebuilds
|
|
16
|
-
* `place_search` ({@link buildPlaceSearchFTS} with `drop: true`) so the candidate build carries
|
|
17
|
-
* Karjaa↔Karis. Proven (FI hard-resolve 69.5 → 85.8 %, coverage 74.4 → 94.0 %); duplicating a
|
|
18
|
-
* place already held under another source is benign — the rows share name_key+coord and the
|
|
19
|
-
* candidate ranking dedupes by score.
|
|
20
|
-
*
|
|
21
|
-
* This is the package home so the canonical `build-unified-wof --geonames-countries`, the
|
|
22
|
-
* pipeline fold (`gazetteer-pipeline/admin/fold-geonames`), AND the `mailwoman gazetteer` commands all share
|
|
23
|
-
* ONE implementation. GeoNames dump = `download.geonames.org/export/dump/<CC>.zip` → `<CC>.txt`
|
|
24
|
-
* (TSV).
|
|
25
5
|
*/
|
|
26
6
|
import { isOfficialLanguage } from "@mailwoman/codex/country";
|
|
27
|
-
import {
|
|
7
|
+
import { readUnquotedTSV } from "@mailwoman/core/fs/delimited";
|
|
8
|
+
import { pathExists } from "@mailwoman/core/fs/readers/stat";
|
|
28
9
|
import { GEONAMES_ID_BASE, GEONAMES_POSTAL_ID_BASE } from "@mailwoman/core/resolver/synthetic-id-ranges";
|
|
29
|
-
import {
|
|
30
|
-
import { TSVSpliterator } from "spliterator";
|
|
31
|
-
/**
|
|
32
|
-
* The four tables the alias fold writes into the range it owns. The purge and the ingest must agree on this list — a
|
|
33
|
-
* table written but not purged is exactly the #1514 defect.
|
|
34
|
-
*/
|
|
10
|
+
import { resolvePathBuilder } from "path-ts";
|
|
35
11
|
const FOLD_OWNED_TABLES = ["spr", "names", "place_population", "ancestors"];
|
|
36
12
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* — so a fold's output is a function of its country list and dumps ALONE, never of what the DB happened to hold first.
|
|
40
|
-
* Returns the rows removed per table.
|
|
41
|
-
*
|
|
42
|
-
* This exists because the synthetic id is a POSITION (`GEONAMES_ID_BASE + n`, counted across the country list in
|
|
43
|
-
* order), not a derivation from the geonameid: change the list, its order, or a dump's contents and every subsequent id
|
|
44
|
-
* shifts. Without the purge, a second fold overwrote the `spr` PREFIX it reached (`INSERT OR REPLACE`) while its
|
|
45
|
-
* `names`/`ancestors` rows merely appended (bare `INSERT`) and `place_population` skipped unpopulated places entirely —
|
|
46
|
-
* so the previous run's names, ancestry and populations stayed bound to ids now describing other places.
|
|
47
|
-
*
|
|
48
|
-
* Measured on the live 2026-08-05 artifact: a 14-country re-fold over the 161-country fold baked into
|
|
49
|
-
* `admin-global-priority.db` put 522,184 of 2,110,096 name rows in the range (24.7 %) on a place from a different
|
|
50
|
-
* country. Gaborone/BW at id 9000000121151 became Aichegg/AT and kept all 26 of its names; Kinshasa's 16,000,000
|
|
51
|
-
* population landed on a Lithuanian hamlet.
|
|
13
|
+
* Deletes every row the GeoNames alias fold owns, with ids in
|
|
14
|
+
* `[GEONAMES_ID_BASE, GEONAMES_POSTAL_ID_BASE)`, and returns the count removed per table.
|
|
52
15
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
16
|
+
* Fold ids are assigned sequentially, so a re-fold without this purge would attach
|
|
17
|
+
* stale names, ancestors and populations to other places.
|
|
18
|
+
* The upper bound leaves the postal and postcode id ranges above it untouched.
|
|
56
19
|
*/
|
|
57
20
|
export function purgeGeonamesAliasRange(db) {
|
|
58
21
|
const removed = {};
|
|
@@ -65,26 +28,18 @@ export function purgeGeonamesAliasRange(db) {
|
|
|
65
28
|
return removed;
|
|
66
29
|
}
|
|
67
30
|
/**
|
|
68
|
-
*
|
|
69
|
-
* places (`P`) in `wanted`.
|
|
31
|
+
* Formats a GeoNames fold progress event as one log line.
|
|
70
32
|
*/
|
|
33
|
+
export function formatGeonamesIngestProgress(event, missingFile) {
|
|
34
|
+
if (event.skipped) {
|
|
35
|
+
return `${event.country}: ${missingFile ? `${missingFile} missing` : "dump missing"} — download from download.geonames.org/export/dump/${event.country}.zip; skipped`;
|
|
36
|
+
}
|
|
37
|
+
return `${event.country}: ${event.places.toLocaleString()} places, ${(event.aliasesRefused ?? 0).toLocaleString()} alt-names refused`;
|
|
38
|
+
}
|
|
71
39
|
async function parseAlternateNamesV2(v2File, cc, wanted) {
|
|
72
40
|
const v2 = new Map();
|
|
73
|
-
// V2 columns (0-indexed): 1 geonameid, 2 isolanguage, 3 name, 4 isPreferredName, 5 isShortName,
|
|
74
|
-
// 6 isColloquial, 7 isHistoric, 8 from, 9 to.
|
|
75
|
-
//
|
|
76
|
-
// Two passes, because historic-ness is a fact about the NAME, not the row: GeoNames splits one
|
|
77
|
-
// spelling across rows — Malabo carries "Santa Isabel" as (es, unflagged) AND as (no-language,
|
|
78
|
-
// isHistoric=1, to=1973). Officialness must see the flags from EVERY row for the spelling, or the
|
|
79
|
-
// colonial-era name sails through on the language-tagged row (the #936 review's Malabo finding).
|
|
80
|
-
// Do NOT condition on isPreferredName instead — it's sparse annotation, not a signal (Turku's sv "Åbo"
|
|
81
|
-
// is unflagged; FI has 1,746 flags across the whole dump).
|
|
82
|
-
//
|
|
83
|
-
// Both passes STREAM the file rather than sharing one materialized array: NO's V2 dump is 33 MB,
|
|
84
|
-
// and a second read off the page cache costs less than holding half a million line strings.
|
|
85
|
-
// `header: false` — the dump is headerless.
|
|
86
41
|
const historicNames = new Set();
|
|
87
|
-
for await (const f of
|
|
42
|
+
for await (const f of readUnquotedTSV(v2File)) {
|
|
88
43
|
if (f[6] === "1" || f[7] === "1" || (f[9] ?? "").trim() !== "") {
|
|
89
44
|
const alt = (f[3] ?? "").trim();
|
|
90
45
|
if (alt && wanted.has(Number(f[1]))) {
|
|
@@ -92,12 +47,11 @@ async function parseAlternateNamesV2(v2File, cc, wanted) {
|
|
|
92
47
|
}
|
|
93
48
|
}
|
|
94
49
|
}
|
|
95
|
-
for await (const f of
|
|
50
|
+
for await (const f of readUnquotedTSV(v2File)) {
|
|
96
51
|
const gid = Number(f[1]);
|
|
97
52
|
if (!wanted.has(gid))
|
|
98
53
|
continue;
|
|
99
54
|
const lang = f[2] ?? "";
|
|
100
|
-
// ISO 639 codes are 2-3 letters; GeoNames' pseudo-codes (post, link, iata, wkdt, …) are 4+.
|
|
101
55
|
if (!/^[a-z]{2,3}$/.test(lang))
|
|
102
56
|
continue;
|
|
103
57
|
const alt = (f[3] ?? "").trim();
|
|
@@ -126,70 +80,59 @@ async function parseAlternateNamesV2(v2File, cc, wanted) {
|
|
|
126
80
|
return v2;
|
|
127
81
|
}
|
|
128
82
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
83
|
+
* Purges the fold's id range, then adds GeoNames `P`-class places and their
|
|
84
|
+
* alternate names for `countries` to `db`.
|
|
85
|
+
* It returns the number of places ingested.
|
|
131
86
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* the candidate build's alias pass.
|
|
87
|
+
* The caller must then rebuild `place_search` with `buildPlaceSearchFTS(db, { drop: true })`
|
|
88
|
+
* to make the new names searchable.
|
|
135
89
|
*/
|
|
136
90
|
export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgress, opts) {
|
|
137
|
-
// Latin-only, no bracket/paren noise GeoNames packs into `alternatenames` ("(( Karis Landskommun ))",
|
|
138
|
-
// airport codes), 2–60 chars, at least one letter (drops bare postcodes/numbers).
|
|
139
91
|
const LATIN_NAME = /^[\p{Script=Latin}\p{M}\s\-'.]{2,60}$/u;
|
|
140
92
|
const clean = (s) => {
|
|
141
93
|
const t = s.trim();
|
|
142
94
|
return t && LATIN_NAME.test(t) && /\p{L}/u.test(t) ? t : null;
|
|
143
95
|
};
|
|
96
|
+
const NAME_NOISE = /[()[\]{}<>|/\\_@#$%^*+=~`"]/u;
|
|
97
|
+
const NAME_MIN_LENGTH = 2;
|
|
98
|
+
const NAME_MAX_LENGTH = 60;
|
|
99
|
+
const cleanAlias = (s) => {
|
|
100
|
+
const t = s.trim();
|
|
101
|
+
return t.length >= NAME_MIN_LENGTH && t.length <= NAME_MAX_LENGTH && /\p{L}/u.test(t) && !NAME_NOISE.test(t)
|
|
102
|
+
? t
|
|
103
|
+
: null;
|
|
104
|
+
};
|
|
144
105
|
const sprInsert = db.prepare(`INSERT OR REPLACE INTO spr (id, parent_id, name, placetype, country, latitude, longitude, min_latitude, min_longitude, max_latitude, max_longitude, is_current, is_deprecated, is_ceased, is_superseded, is_superseding, lastmodified) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
145
106
|
const namesInsert = db.prepare(`INSERT INTO names (id, name, placetype, country, language, privateuse, official, lastmodified) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
146
107
|
const populationInsert = db.prepare(`INSERT OR REPLACE INTO place_population (id, population) VALUES (?, ?)`);
|
|
147
|
-
// #267 admin linkage: ancestor rows (locality→region→country) so parentID scoping + adminCoherence reach
|
|
148
|
-
// the gap countries. Only used for a country in opts.adminForCountries.
|
|
149
108
|
const ancestorInsert = db.prepare(`INSERT INTO ancestors (id, ancestor_id, ancestor_placetype, lastmodified) VALUES (?, ?, ?, 0)`);
|
|
150
109
|
const report = (event, missingFile) => {
|
|
151
110
|
if (onProgress) {
|
|
152
111
|
onProgress(event);
|
|
153
112
|
}
|
|
154
|
-
else if (event.skipped) {
|
|
155
|
-
console.error(` GeoNames ${event.country}: ${missingFile} missing — download from download.geonames.org/export/dump/${event.country}.zip; skipped`);
|
|
156
|
-
}
|
|
157
113
|
else {
|
|
158
|
-
console.error(` GeoNames ${event
|
|
114
|
+
console.error(` GeoNames ${formatGeonamesIngestProgress(event, missingFile)}`);
|
|
159
115
|
}
|
|
160
116
|
};
|
|
161
117
|
let id = GEONAMES_ID_BASE;
|
|
162
118
|
let total = 0;
|
|
163
119
|
db.exec("BEGIN");
|
|
164
|
-
// #1514: clear the range before writing it. Inside the transaction, so a fold that throws leaves the
|
|
165
|
-
// DB as it found it rather than half-purged. See purgeGeonamesAliasRange for why the ids demand this.
|
|
166
120
|
purgeGeonamesAliasRange(db);
|
|
167
121
|
for (const cc of countries) {
|
|
168
|
-
const file =
|
|
122
|
+
const file = resolvePathBuilder(geonamesDir, `${cc}.txt`);
|
|
169
123
|
if (!(await pathExists(file))) {
|
|
170
|
-
report({ country: cc, places: 0, skipped: true }, file);
|
|
124
|
+
report({ country: cc, places: 0, skipped: true, aliasesRefused: null }, file);
|
|
171
125
|
continue;
|
|
172
126
|
}
|
|
173
127
|
let nc = 0;
|
|
174
|
-
|
|
128
|
+
let refused = 0;
|
|
175
129
|
const addAdmin = opts?.adminForCountries?.has(cc) ?? false;
|
|
176
|
-
const v2File = opts?.alternateDir ?
|
|
130
|
+
const v2File = opts?.alternateDir ? resolvePathBuilder(opts.alternateDir, `${cc}.txt`) : undefined;
|
|
177
131
|
const readV2 = Boolean(v2File && (await pathExists(v2File)));
|
|
178
|
-
// Survey pass. The dump is STREAMED — NO's is 71 MB and only the caller knows which country
|
|
179
|
-
// comes next — so what a later pass needs has to be collected here rather than re-scanned off a
|
|
180
|
-
// materialized array. Two things qualify, and both are small: the P-class geonameid set the V2
|
|
181
|
-
// decoration is restricted to, and the handful of A-class rows the admin pre-pass writes (one
|
|
182
|
-
// PCL* + the ADM1s). Everything else is re-read in the emit pass below. Neither is wanted
|
|
183
|
-
// without V2 tags or admin, and then the pass is skipped rather than read for nothing.
|
|
184
|
-
//
|
|
185
|
-
// GeoNames dump columns (0-indexed): 0 geonameid, 1 name, 2 asciiname, 3 alternatenames, 4 lat, 5 lon,
|
|
186
|
-
// 6 feature_class, 7 feature_code, 10 admin1 code, 14 pop.
|
|
187
|
-
//
|
|
188
|
-
// `header: false` — the dump is headerless, so row 1 is a place, not column names.
|
|
189
132
|
const wanted = new Set();
|
|
190
133
|
const adminRows = [];
|
|
191
134
|
if (readV2 || addAdmin) {
|
|
192
|
-
for await (const f of
|
|
135
|
+
for await (const f of readUnquotedTSV(file)) {
|
|
193
136
|
if (f[6] === "P") {
|
|
194
137
|
if (readV2) {
|
|
195
138
|
wanted.add(Number(f[0]));
|
|
@@ -201,12 +144,7 @@ export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgre
|
|
|
201
144
|
}
|
|
202
145
|
}
|
|
203
146
|
}
|
|
204
|
-
// #936: V2 tags for this country's P-class rows — geonameid → exact alias spelling → tag. The V2
|
|
205
|
-
// dump repeats one spelling under several languages ("Åbo" sv/da/no); the merged tag is official /
|
|
206
|
-
// preferred if ANY qualifying row is.
|
|
207
147
|
const v2 = readV2 ? await parseAlternateNamesV2(v2File, cc, wanted) : undefined;
|
|
208
|
-
// #267 admin pre-pass (gap countries): fold the country (PCLI) + regions (ADM1), self+ancestry them, and
|
|
209
|
-
// build the admin1→region map the localities link through. Point bbox (GeoNames gives a centroid only).
|
|
210
148
|
let countryID = -1;
|
|
211
149
|
const adminMap = new Map();
|
|
212
150
|
if (addAdmin) {
|
|
@@ -217,11 +155,8 @@ export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgre
|
|
|
217
155
|
const lat = Number(f[4]) || 0;
|
|
218
156
|
const lon = Number(f[5]) || 0;
|
|
219
157
|
if (f[7]?.startsWith("PCL")) {
|
|
220
|
-
// Any country-level political entity — PCLI (independent), PCLD (dependent territory),
|
|
221
|
-
// PCLF (freely associated), PCLS (special administrative region: HK/MO/PS). All are the
|
|
222
|
-
// country tier; restricting to PCLI left those ~17 territories without a country row.
|
|
223
158
|
if (countryID >= 0)
|
|
224
|
-
continue;
|
|
159
|
+
continue;
|
|
225
160
|
countryID = id++;
|
|
226
161
|
sprInsert.run(countryID, -1, aname, "country", cc, lat, lon, lat, lon, lat, lon, 1, 0, 0, 0, 0, 0);
|
|
227
162
|
namesInsert.run(countryID, aname, "country", cc, "", "", 0, 0);
|
|
@@ -235,7 +170,6 @@ export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgre
|
|
|
235
170
|
adminMap.set(f[10], rid);
|
|
236
171
|
}
|
|
237
172
|
}
|
|
238
|
-
// Re-parent regions + ancestor them to the (now-known) country.
|
|
239
173
|
if (countryID >= 0) {
|
|
240
174
|
for (const rid of adminMap.values()) {
|
|
241
175
|
db.prepare("UPDATE spr SET parent_id = ? WHERE id = ?").run(countryID, rid);
|
|
@@ -243,10 +177,9 @@ export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgre
|
|
|
243
177
|
}
|
|
244
178
|
}
|
|
245
179
|
}
|
|
246
|
-
|
|
247
|
-
for await (const f of TSVSpliterator.fromAsync(file, { header: false })) {
|
|
180
|
+
for await (const f of readUnquotedTSV(file)) {
|
|
248
181
|
if (f[6] !== "P")
|
|
249
|
-
continue;
|
|
182
|
+
continue;
|
|
250
183
|
const lat = Number(f[4]);
|
|
251
184
|
const lon = Number(f[5]);
|
|
252
185
|
if (!Number.isFinite(lat) || !Number.isFinite(lon))
|
|
@@ -255,18 +188,10 @@ export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgre
|
|
|
255
188
|
if (!name)
|
|
256
189
|
continue;
|
|
257
190
|
const nid = id++;
|
|
258
|
-
// #267: link to the locality's region (else country) for gap countries; -1 (orphan) otherwise.
|
|
259
191
|
const regionID = addAdmin ? (adminMap.get(f[10] ?? "") ?? -1) : -1;
|
|
260
192
|
const parentID = regionID >= 0 ? regionID : addAdmin && countryID >= 0 ? countryID : -1;
|
|
261
|
-
// Point bbox — a GeoNames row is a centroid; the candidate's region-bbox disambiguation just
|
|
262
|
-
// sees it as contained in itself, fine for a locality.
|
|
263
193
|
sprInsert.run(nid, parentID, name, "locality", cc, lat, lon, lat, lon, lat, lon, 1, 0, 0, 0, 0, 0);
|
|
264
194
|
namesInsert.run(nid, name, "locality", cc, "", "", 0, 0);
|
|
265
|
-
// The SELF row is unconditional (#1514). `populateAncestors` writes one for every spr row it
|
|
266
|
-
// sees, so a full build's freeze phase produces it either way — but the freeze does not run on
|
|
267
|
-
// the fold-on-copy path, and since the purge now clears this range the fold has to emit
|
|
268
|
-
// everything the closure would. Measured on the 161-country fold: 212,993 self rows, exactly the
|
|
269
|
-
// non-gap countries' localities, which is what the base artifact carried and a fold-on-copy lost.
|
|
270
195
|
ancestorInsert.run(nid, nid, "locality");
|
|
271
196
|
if (addAdmin) {
|
|
272
197
|
if (regionID >= 0) {
|
|
@@ -279,7 +204,10 @@ export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgre
|
|
|
279
204
|
const seen = new Set([name]);
|
|
280
205
|
const tags = v2?.get(Number(f[0]));
|
|
281
206
|
for (const raw of [f[2] ?? "", ...(f[3] ? f[3].split(",") : [])]) {
|
|
282
|
-
const alt =
|
|
207
|
+
const alt = cleanAlias(raw);
|
|
208
|
+
if (!alt && raw.trim()) {
|
|
209
|
+
refused++;
|
|
210
|
+
}
|
|
283
211
|
if (alt && !seen.has(alt)) {
|
|
284
212
|
seen.add(alt);
|
|
285
213
|
const tag = tags?.get(alt);
|
|
@@ -292,7 +220,7 @@ export async function ingestGeonamesAliases(db, countries, geonamesDir, onProgre
|
|
|
292
220
|
}
|
|
293
221
|
nc++;
|
|
294
222
|
}
|
|
295
|
-
report({ country: cc, places: nc, skipped: false });
|
|
223
|
+
report({ country: cc, places: nc, skipped: false, aliasesRefused: refused });
|
|
296
224
|
total += nc;
|
|
297
225
|
}
|
|
298
226
|
db.exec("COMMIT");
|