@mailwoman/resolver-wof-sqlite 9.1.0 → 9.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 +28 -9
- package/address-point-interpolation.ts +18 -8
- package/address-point-schema.ts +18 -6
- package/address-point.ts +111 -18
- package/ancestry.ts +9 -6
- package/build-candidate.ts +200 -163
- package/build-slim.ts +3 -3
- package/candidate/alias-bags.ts +54 -0
- package/candidate/ancestors-sidecar.ts +206 -0
- package/candidate/country-display-names.ts +79 -0
- package/candidate/name-roles.ts +237 -0
- package/candidate/own-name.ts +146 -0
- package/candidate/place-attrs.ts +44 -0
- package/candidate/shard-fold.ts +137 -0
- package/candidate-ancestors-schema.ts +195 -0
- package/candidate-fts.ts +4 -2
- package/candidate-importance.ts +2 -1
- package/candidate-lookup.ts +439 -186
- package/candidate-schema.ts +33 -5
- package/candidate-scoring.ts +268 -0
- package/capital-schema.ts +90 -0
- package/capitals.ts +148 -0
- package/coincident-roles.ts +69 -10
- package/convention-schema.ts +72 -0
- package/convention.ts +2 -2
- package/coverage-manifest-schema.ts +7 -7
- package/currency-backfill.ts +249 -0
- package/exact-match.ts +104 -0
- package/fst-autocomplete.ts +91 -119
- package/fst-builder.ts +14 -12
- package/fst-freshness.ts +2 -2
- package/fts-query.ts +1 -1
- package/fts.ts +4 -4
- package/geonames-postal.ts +2 -2
- package/index.ts +18 -14
- package/interpolation.ts +113 -19
- package/lookup.ts +110 -591
- package/name-score.ts +6 -4
- package/out/address-point-interpolation.d.ts.map +1 -1
- package/out/address-point-interpolation.js +13 -7
- package/out/address-point-interpolation.js.map +1 -1
- package/out/address-point-schema.d.ts +16 -6
- package/out/address-point-schema.d.ts.map +1 -1
- package/out/address-point-schema.js.map +1 -1
- package/out/address-point.d.ts.map +1 -1
- package/out/address-point.js +70 -14
- package/out/address-point.js.map +1 -1
- package/out/ancestry.d.ts +2 -2
- package/out/ancestry.d.ts.map +1 -1
- package/out/ancestry.js +5 -6
- package/out/ancestry.js.map +1 -1
- package/out/build-candidate.d.ts +75 -0
- package/out/build-candidate.d.ts.map +1 -1
- package/out/build-candidate.js +120 -122
- package/out/build-candidate.js.map +1 -1
- package/out/build-slim.d.ts +1 -1
- package/out/build-slim.js +3 -3
- package/out/build-slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +17 -0
- package/out/candidate/alias-bags.d.ts.map +1 -0
- package/out/candidate/alias-bags.js +39 -0
- package/out/candidate/alias-bags.js.map +1 -0
- package/out/candidate/ancestors-sidecar.d.ts +33 -0
- package/out/candidate/ancestors-sidecar.d.ts.map +1 -0
- package/out/candidate/ancestors-sidecar.js +140 -0
- package/out/candidate/ancestors-sidecar.js.map +1 -0
- package/out/candidate/country-display-names.d.ts +35 -0
- package/out/candidate/country-display-names.d.ts.map +1 -0
- package/out/candidate/country-display-names.js +59 -0
- package/out/candidate/country-display-names.js.map +1 -0
- package/out/candidate/name-roles.d.ts +55 -0
- package/out/candidate/name-roles.d.ts.map +1 -0
- package/out/candidate/name-roles.js +165 -0
- package/out/candidate/name-roles.js.map +1 -0
- package/out/candidate/own-name.d.ts +50 -0
- package/out/candidate/own-name.d.ts.map +1 -0
- package/out/candidate/own-name.js +132 -0
- package/out/candidate/own-name.js.map +1 -0
- package/out/candidate/place-attrs.d.ts +43 -0
- package/out/candidate/place-attrs.d.ts.map +1 -0
- package/out/candidate/place-attrs.js +15 -0
- package/out/candidate/place-attrs.js.map +1 -0
- package/out/candidate/shard-fold.d.ts +31 -0
- package/out/candidate/shard-fold.d.ts.map +1 -0
- package/out/candidate/shard-fold.js +104 -0
- package/out/candidate/shard-fold.js.map +1 -0
- package/out/candidate-ancestors-schema.d.ts +150 -0
- package/out/candidate-ancestors-schema.d.ts.map +1 -0
- package/out/candidate-ancestors-schema.js +123 -0
- package/out/candidate-ancestors-schema.js.map +1 -0
- package/out/candidate-fts.d.ts +4 -2
- package/out/candidate-fts.d.ts.map +1 -1
- package/out/candidate-fts.js +4 -2
- package/out/candidate-fts.js.map +1 -1
- package/out/candidate-importance.d.ts.map +1 -1
- package/out/candidate-importance.js +1 -1
- package/out/candidate-importance.js.map +1 -1
- package/out/candidate-lookup.d.ts +22 -45
- package/out/candidate-lookup.d.ts.map +1 -1
- package/out/candidate-lookup.js +340 -135
- package/out/candidate-lookup.js.map +1 -1
- package/out/candidate-schema.d.ts +30 -6
- package/out/candidate-schema.d.ts.map +1 -1
- package/out/candidate-schema.js +3 -0
- package/out/candidate-schema.js.map +1 -1
- package/out/candidate-scoring.d.ts +34 -0
- package/out/candidate-scoring.d.ts.map +1 -0
- package/out/candidate-scoring.js +200 -0
- package/out/candidate-scoring.js.map +1 -0
- package/out/capital-schema.d.ts +51 -0
- package/out/capital-schema.d.ts.map +1 -0
- package/out/capital-schema.js +63 -0
- package/out/capital-schema.js.map +1 -0
- package/out/capitals.d.ts +69 -0
- package/out/capitals.d.ts.map +1 -0
- package/out/capitals.js +98 -0
- package/out/capitals.js.map +1 -0
- package/out/coincident-roles.d.ts +7 -0
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +42 -8
- package/out/coincident-roles.js.map +1 -1
- package/out/convention-schema.d.ts +51 -0
- package/out/convention-schema.d.ts.map +1 -0
- package/out/convention-schema.js +34 -0
- package/out/convention-schema.js.map +1 -0
- package/out/convention.d.ts +1 -1
- package/out/convention.js +2 -2
- package/out/coverage-manifest-schema.js +3 -7
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +46 -0
- package/out/currency-backfill.d.ts.map +1 -0
- package/out/currency-backfill.js +180 -0
- package/out/currency-backfill.js.map +1 -0
- package/out/exact-match.d.ts +25 -0
- package/out/exact-match.d.ts.map +1 -0
- package/out/exact-match.js +89 -0
- package/out/exact-match.js.map +1 -0
- package/out/fst-autocomplete.d.ts +11 -11
- package/out/fst-autocomplete.d.ts.map +1 -1
- package/out/fst-autocomplete.js +82 -99
- package/out/fst-autocomplete.js.map +1 -1
- package/out/fst-builder.d.ts.map +1 -1
- package/out/fst-builder.js +11 -12
- package/out/fst-builder.js.map +1 -1
- package/out/fst-freshness.d.ts +2 -2
- package/out/fst-freshness.js +2 -2
- package/out/fts-query.js +1 -1
- package/out/fts-query.js.map +1 -1
- package/out/fts.d.ts +4 -4
- package/out/fts.js +4 -4
- package/out/geonames-postal.d.ts +2 -2
- package/out/geonames-postal.js +2 -2
- package/out/index.d.ts +3 -2
- package/out/index.d.ts.map +1 -1
- package/out/index.js +2 -2
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +8 -0
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +91 -19
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +4 -5
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +94 -468
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +0 -10
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js +6 -4
- package/out/name-score.js.map +1 -1
- package/out/place-importance-schema.d.ts +42 -5
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +54 -8
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi-lookup.d.ts +1 -1
- package/out/poi-lookup.d.ts.map +1 -1
- package/out/poi-lookup.js +12 -13
- package/out/poi-lookup.js.map +1 -1
- package/out/poi-schema.d.ts +7 -3
- package/out/poi-schema.d.ts.map +1 -1
- package/out/poi-schema.js.map +1 -1
- package/out/polygon-schema.d.ts +37 -0
- package/out/polygon-schema.d.ts.map +1 -0
- package/out/polygon-schema.js +23 -0
- package/out/polygon-schema.js.map +1 -0
- package/out/postal-city-alias-lookup.d.ts +1 -1
- package/out/postal-city-alias-lookup.js +1 -1
- package/out/postal-city-candidate-schema.d.ts +2 -1
- package/out/postal-city-candidate-schema.d.ts.map +1 -1
- package/out/postal-city-candidate-schema.js.map +1 -1
- package/out/postcode-point-lookup.d.ts +1 -1
- package/out/postcode-point-lookup.js +1 -1
- package/out/primary-preference.d.ts +125 -0
- package/out/primary-preference.d.ts.map +1 -0
- package/out/primary-preference.js +138 -0
- package/out/primary-preference.js.map +1 -0
- package/out/proximity-rerank.d.ts +77 -0
- package/out/proximity-rerank.d.ts.map +1 -0
- package/out/proximity-rerank.js +86 -0
- package/out/proximity-rerank.js.map +1 -0
- package/out/region-keys.d.ts +47 -0
- package/out/region-keys.d.ts.map +1 -0
- package/out/region-keys.js +121 -0
- package/out/region-keys.js.map +1 -0
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +6 -9
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +1 -1
- package/out/search-fetch.d.ts +57 -0
- package/out/search-fetch.d.ts.map +1 -0
- package/out/search-fetch.js +183 -0
- package/out/search-fetch.js.map +1 -0
- package/out/sharding.d.ts +3 -3
- package/out/sharding.js +1 -1
- package/out/sqlite-convention-source.d.ts +1 -1
- package/out/sqlite-convention-source.js +1 -1
- package/out/sqlite-utils.d.ts +19 -1
- package/out/sqlite-utils.d.ts.map +1 -1
- package/out/sqlite-utils.js +19 -1
- package/out/sqlite-utils.js.map +1 -1
- package/out/street-centroid-schema.d.ts +7 -2
- package/out/street-centroid-schema.d.ts.map +1 -1
- package/out/street-centroid-schema.js.map +1 -1
- package/out/street-centroid.d.ts.map +1 -1
- package/out/street-centroid.js +7 -7
- package/out/street-centroid.js.map +1 -1
- package/out/street-normalize.d.ts +82 -9
- package/out/street-normalize.d.ts.map +1 -1
- package/out/street-normalize.js +175 -9
- package/out/street-normalize.js.map +1 -1
- package/out/street-segment-schema.d.ts +6 -2
- package/out/street-segment-schema.d.ts.map +1 -1
- package/out/street-segment-schema.js.map +1 -1
- package/out/types.d.ts +35 -1
- package/out/types.d.ts.map +1 -1
- package/out/unified-schema.d.ts +1 -1
- package/out/unified-schema.js +1 -1
- package/out/uprn-lookup.d.ts +85 -0
- package/out/uprn-lookup.d.ts.map +1 -0
- package/out/uprn-lookup.js +152 -0
- package/out/uprn-lookup.js.map +1 -0
- package/out/uprn-schema.d.ts +93 -0
- package/out/uprn-schema.d.ts.map +1 -0
- package/out/uprn-schema.js +78 -0
- package/out/uprn-schema.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +141 -0
- package/out/weights-overlay-linker.d.ts.map +1 -0
- package/out/weights-overlay-linker.js +259 -0
- package/out/weights-overlay-linker.js.map +1 -0
- package/package.json +288 -16
- package/place-importance-schema.ts +64 -15
- package/poi-lookup.ts +12 -13
- package/poi-schema.ts +8 -3
- package/polygon-schema.ts +47 -0
- package/postal-city-alias-lookup.ts +1 -1
- package/postal-city-candidate-schema.ts +3 -1
- package/postcode-point-lookup.ts +1 -1
- package/primary-preference.ts +207 -0
- package/proximity-rerank.ts +120 -0
- package/region-keys.ts +144 -0
- package/reverse.ts +17 -16
- package/schema.ts +1 -1
- package/search-fetch.ts +256 -0
- package/sharding.ts +3 -3
- package/sqlite-convention-source.ts +1 -1
- package/sqlite-utils.ts +43 -2
- package/street-centroid-schema.ts +8 -2
- package/street-centroid.ts +13 -8
- package/street-normalize.ts +252 -23
- package/street-segment-schema.ts +7 -2
- package/types.ts +35 -1
- package/unified-schema.ts +1 -1
- package/uprn-lookup.ts +210 -0
- package/uprn-schema.ts +124 -0
- package/weights-overlay-linker.ts +377 -0
- package/geo.ts +0 -121
- package/out/geo.d.ts +0 -74
- package/out/geo.d.ts.map +0 -1
- package/out/geo.js +0 -71
- package/out/geo.js.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Typed schema for the polygon sidecar (`wof-polygons.db`) — the one table `WOFReverseGeocoder` probes for a
|
|
7
|
+
* place's geometry. The interface is the read/write contract and {@link createPolygonsTable} creates the table, so a
|
|
8
|
+
* column added to one is a compile error against the other.
|
|
9
|
+
*
|
|
10
|
+
* The sidecar is OPTIONAL to the reverse geocoder: without it every result falls back to a centroid, so the reader
|
|
11
|
+
* checks for the table's presence rather than assuming it.
|
|
12
|
+
*/
|
|
13
|
+
import type { Kysely } from "kysely";
|
|
14
|
+
/**
|
|
15
|
+
* One admin polygon, keyed by WOF id.
|
|
16
|
+
*/
|
|
17
|
+
export interface PolygonsTable {
|
|
18
|
+
id: number;
|
|
19
|
+
/**
|
|
20
|
+
* The GeoJSON geometry, JSON-encoded. A row that fails to parse reads as no-polygon, never as an error — a malformed
|
|
21
|
+
* geometry must not fail the whole reverse query.
|
|
22
|
+
*/
|
|
23
|
+
geom: string;
|
|
24
|
+
}
|
|
25
|
+
export interface PolygonDatabase {
|
|
26
|
+
polygons: PolygonsTable;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The slice of a Kysely handle the polygon DDL touches. Kysely is invariant in its schema parameter, so naming only
|
|
30
|
+
* `schema` lets a builder holding a wider handle pass it without a cast.
|
|
31
|
+
*/
|
|
32
|
+
export type PolygonSchemaHandle = Pick<Kysely<PolygonDatabase>, "schema">;
|
|
33
|
+
/**
|
|
34
|
+
* Create the `polygons` table — called before the streaming bulk load.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createPolygonsTable(db: PolygonSchemaHandle): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=polygon-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-schema.d.ts","sourceRoot":"","sources":["../polygon-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEpC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,aAAa,CAAA;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,CAAA;AAEzE;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Typed schema for the polygon sidecar (`wof-polygons.db`) — the one table `WOFReverseGeocoder` probes for a
|
|
7
|
+
* place's geometry. The interface is the read/write contract and {@link createPolygonsTable} creates the table, so a
|
|
8
|
+
* column added to one is a compile error against the other.
|
|
9
|
+
*
|
|
10
|
+
* The sidecar is OPTIONAL to the reverse geocoder: without it every result falls back to a centroid, so the reader
|
|
11
|
+
* checks for the table's presence rather than assuming it.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Create the `polygons` table — called before the streaming bulk load.
|
|
15
|
+
*/
|
|
16
|
+
export async function createPolygonsTable(db) {
|
|
17
|
+
await db.schema
|
|
18
|
+
.createTable("polygons")
|
|
19
|
+
.addColumn("id", "integer", (column) => column.primaryKey())
|
|
20
|
+
.addColumn("geom", "text", (column) => column.notNull())
|
|
21
|
+
.execute();
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=polygon-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-schema.js","sourceRoot":"","sources":["../polygon-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA0BH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAuB;IAChE,MAAM,EAAE,CAAC,MAAM;SACb,WAAW,CAAC,UAAU,CAAC;SACvB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;SAC3D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;SACvD,OAAO,EAAE,CAAA;AACZ,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Node reader over the POSTAL-CITY ALIAS table (`postal-city-alias-<cc>.db`) — the observed
|
|
7
7
|
* `postal_city → geo_locality` aliases per postcode (`build-postal-city-alias.ts`). Consumed by
|
|
8
|
-
* {@link
|
|
8
|
+
* {@link WOFSQLitePlaceLookup}'s coordinate-first locality scorer: a user-typed postal city
|
|
9
9
|
* ("Antioch", postcode 37013) becomes a name-match alias for the geographic locality the postcode
|
|
10
10
|
* actually sits in ("Nashville"), so the right place tiers to the top instead of a same-named
|
|
11
11
|
* town in another state. Opt-in — the lookup is only constructed when a path is supplied, and
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Node reader over the POSTAL-CITY ALIAS table (`postal-city-alias-<cc>.db`) — the observed
|
|
7
7
|
* `postal_city → geo_locality` aliases per postcode (`build-postal-city-alias.ts`). Consumed by
|
|
8
|
-
* {@link
|
|
8
|
+
* {@link WOFSQLitePlaceLookup}'s coordinate-first locality scorer: a user-typed postal city
|
|
9
9
|
* ("Antioch", postcode 37013) becomes a name-match alias for the geographic locality the postcode
|
|
10
10
|
* actually sits in ("Nashville"), so the right place tiers to the top instead of a same-named
|
|
11
11
|
* town in another state. Opt-in — the lookup is only constructed when a path is supplied, and
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* untouched.
|
|
19
19
|
*/
|
|
20
20
|
import { type Kysely } from "kysely";
|
|
21
|
+
import type { NameKey } from "./street-normalize.ts";
|
|
21
22
|
/**
|
|
22
23
|
* One postal-city → geo-locality edge, keyed exactly by `(name_key, postcode)`. The probe returns the geographic
|
|
23
24
|
* locality directly; the denormalized name/coord avoid a join back to `candidate`.
|
|
@@ -26,7 +27,7 @@ export interface PostalCityCandidateTable {
|
|
|
26
27
|
/**
|
|
27
28
|
* {@link normalizeLocalityForKey} of the postal-city name — the build/query-consistent probe key.
|
|
28
29
|
*/
|
|
29
|
-
name_key:
|
|
30
|
+
name_key: NameKey;
|
|
30
31
|
/**
|
|
31
32
|
* The postcode the alias is scoped to (the second half of the exact key).
|
|
32
33
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postal-city-candidate-schema.d.ts","sourceRoot":"","sources":["../postal-city-candidate-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAO,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEzC;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACxC;;OAEG;IACH,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"postal-city-candidate-schema.d.ts","sourceRoot":"","sources":["../postal-city-candidate-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAO,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAEpD;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACxC;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC3C,qBAAqB,EAAE,wBAAwB,CAAA;CAC/C;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B,0BAA0B,CAAA;AAElE;;GAEG;AACH,eAAO,MAAM,6BAA6B,8EAOhC,CAAA;AAEV;;;;GAIG;AACH,wBAAsB,8BAA8B,CAAC,EAAE,EAAE,MAAM,CAAC,2BAA2B,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAc3G"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postal-city-candidate-schema.js","sourceRoot":"","sources":["../postal-city-candidate-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,GAAG,EAAe,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"postal-city-candidate-schema.js","sourceRoot":"","sources":["../postal-city-candidate-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,GAAG,EAAe,MAAM,QAAQ,CAAA;AAoCzC;;GAEG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,uBAAuB,CAAA;AAElE;;GAEG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC5C,UAAU;IACV,UAAU;IACV,QAAQ;IACR,MAAM;IACN,UAAU;IACV,WAAW;CACF,CAAA;AAEV;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,EAAuC;IAC3F,MAAM,EAAE,CAAC,MAAM;SACb,WAAW,CAAC,2BAA2B,CAAC;SACxC,WAAW,EAAE;SACb,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACjD,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACjD,SAAS,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAClD,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAC7C,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SACjD,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;SAClD,uBAAuB,CAAC,0BAA0B,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC9E,0FAA0F;SACzF,SAAS,CAAC,GAAG,CAAA,eAAe,CAAC;SAC7B,OAAO,EAAE,CAAA;AACZ,CAAC"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* anchor only needs "does this string exist as a postcode, in which countries, near where". A
|
|
14
14
|
* future WASM build swaps this for an FST-backed resolver behind the same `lookup()` seam.
|
|
15
15
|
*
|
|
16
|
-
* Why multiple shards instead of the multi-shard `
|
|
16
|
+
* Why multiple shards instead of the multi-shard `WOFSQLitePlaceLookup`: that resolver routes a
|
|
17
17
|
* query to ONE shard by placetype, but every postcode shard shares `placetype='postalcode'`, so a
|
|
18
18
|
* single query could only ever hit one country's shard. The anchor needs the union across
|
|
19
19
|
* countries to build its country posterior, so it queries each shard directly.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* anchor only needs "does this string exist as a postcode, in which countries, near where". A
|
|
14
14
|
* future WASM build swaps this for an FST-backed resolver behind the same `lookup()` seam.
|
|
15
15
|
*
|
|
16
|
-
* Why multiple shards instead of the multi-shard `
|
|
16
|
+
* Why multiple shards instead of the multi-shard `WOFSQLitePlaceLookup`: that resolver routes a
|
|
17
17
|
* query to ONE shard by placetype, but every postcode shard shares `placetype='postalcode'`, so a
|
|
18
18
|
* single query could only ever hit one country's shard. The anchor needs the union across
|
|
19
19
|
* countries to build its country posterior, so it queries each shard directly.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Bounded cross-country PRIMARY-NAME preference over a population-ordered candidate row set — the
|
|
7
|
+
* `is_primary` ranking signal, PURE and platform-free so the Node candidate lookup
|
|
8
|
+
* (`candidate-lookup.ts`) and the browser twin (`docs/src/shared/httpvfs-resolver.ts`) rank with the
|
|
9
|
+
* SAME function rather than two copies that drift (the #861 server↔demo parity contract).
|
|
10
|
+
*
|
|
11
|
+
* Only type imports and arithmetic live here: anything with a `node:` import stays out.
|
|
12
|
+
*/
|
|
13
|
+
import type { CandidateTable } from "./candidate-schema.ts";
|
|
14
|
+
/**
|
|
15
|
+
* The row shape the re-rank needs. `is_primary` is optional: a reader over an artifact vintage that predates the column
|
|
16
|
+
* omits it from the SELECT, no row reads as primary, and the re-rank no-ops by construction — the exact degradation the
|
|
17
|
+
* browser reader's vintage guard relies on.
|
|
18
|
+
*/
|
|
19
|
+
export type PrimaryPreferenceRow = Pick<CandidateTable, "neg_rank" | "country_id"> & Partial<Pick<CandidateTable, "is_primary" | "placetype_id" | "population" | "name_role">>;
|
|
20
|
+
/**
|
|
21
|
+
* Bounded PRIMARY-NAME preference across a CROSS-COUNTRY name collision (the `is_primary` ranking signal).
|
|
22
|
+
*
|
|
23
|
+
* The raw candidate order is population-first (`neg_rank ASC`) and treats an ALIAS row (a place's alt-name / exonym,
|
|
24
|
+
* `is_primary=0`) and a PRIMARY-name row (`is_primary=1`) on equal footing. So a foreign place whose transliterated
|
|
25
|
+
* exonym coincidentally normalizes to a query — Changchun CN stores the Turkish exonym "Çançun" (`name_key="cancun"`),
|
|
26
|
+
* 4.19 M pop — outranks the PRIMARY-name place the query actually means (Cancún MX, 0.89 M pop). This penalty makes a
|
|
27
|
+
* same-key alias have to clear a population MARGIN over a foreign primary before it wins.
|
|
28
|
+
*
|
|
29
|
+
* It is deliberately NOT a dominant sort key (no `ORDER BY is_primary DESC`, which would make every primary outrank
|
|
30
|
+
* every alias and break the alt-names users depend on — "NYC"→New York, "LA"→Los Angeles, "Frisco"→San Francisco). Two
|
|
31
|
+
* bounds keep it a soft prior:
|
|
32
|
+
*
|
|
33
|
+
* 1. **Cross-country only.** The penalty applies to an alias ONLY when the top-population primary sharing the key is in a
|
|
34
|
+
* DIFFERENT country. A SAME-country nickname contest (San Francisco's alias "Frisco" vs the primary Frisco, TX —
|
|
35
|
+
* both US) is left on pure population, so the legitimate alias still wins.
|
|
36
|
+
* 2. **Population-bounded.** The penalty is {@link PRIMARY_PREFERENCE_LOG10} in log10-population units — an alias must be
|
|
37
|
+
* at least 10x more populous than the foreign primary to still win. So a genuinely dominant alias keeps winning
|
|
38
|
+
* ("Los Angeles" over La, Ghana — gap 1.6; "Las Vegas" over Vegas, Cuba — gap 2.4) while a near-tie coincidental
|
|
39
|
+
* collision defers to the primary (Cancún over Changchun — gap 0.7).
|
|
40
|
+
*/
|
|
41
|
+
export declare const PRIMARY_PREFERENCE_LOG10 = 1;
|
|
42
|
+
/**
|
|
43
|
+
* Over-fetch cap for {@link rankByPrimaryPreference}: the candidate rows for one `name_key` (all same-name places
|
|
44
|
+
* worldwide) are re-ranked in-process, so the probe fetches this many (population-ordered) before the re-rank rather
|
|
45
|
+
* than the caller's small `limit`, ensuring the intended primary isn't cut below the fold by a cluster of more-populous
|
|
46
|
+
* foreign aliases. Bounded and small — a single contiguous B-tree scan.
|
|
47
|
+
*/
|
|
48
|
+
export declare const RERANK_FETCH = 64;
|
|
49
|
+
/**
|
|
50
|
+
* A candidate row annotated with the {@link rankByPrimaryPreference} effective rank + the exact-tier demotion flag.
|
|
51
|
+
*/
|
|
52
|
+
export type RankedRow<R> = R & {
|
|
53
|
+
/**
|
|
54
|
+
* `neg_rank` plus the bounded cross-country alias penalty — the value the row is ORDERED by, and the base the emitted
|
|
55
|
+
* `prominence` is derived from (so the resolver walk's `prominence ?? score` sort, `resolve.ts`, agrees with this
|
|
56
|
+
* order; the raw `score`/`neg_rank` is left intact for the walk's `minWinningScore` gate).
|
|
57
|
+
*/
|
|
58
|
+
effectiveNegRank: number;
|
|
59
|
+
/**
|
|
60
|
+
* True when this row is a cross-country alias that LOST the bounded population contest to the same-key primary — a
|
|
61
|
+
* coincidental foreign exonym (Changchun's "Çançun" for "Cancun"). Such a row is dropped out of the exact-match tier
|
|
62
|
+
* (`exactMatch=false`) so the resolver walk's country pin — the model's `anchorPosterior`, which "never crosses the
|
|
63
|
+
* exact/partial boundary" (`resolve.ts`) — can't ride a spurious posterior (CN 0.86 for "Cancun") back over the
|
|
64
|
+
* primary. Only the LOSING foreign alias is demoted; a dominant alias (Los Angeles over La, Ghana) keeps its exact
|
|
65
|
+
* tier, and a same-country nickname (San Francisco's "Frisco") is never touched.
|
|
66
|
+
*/
|
|
67
|
+
demoted: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* True when this row came from the TYPO-CORRECTOR tier — the FTS5-trigram fallback that fires only after the exact
|
|
70
|
+
* and qualifier-strip probes both missed. Such a row answers a query the gazetteer does not contain, so it is a fuzzy
|
|
71
|
+
* match by construction and must not claim `exactMatch` (#17). Recall is unaffected: the row is still returned, still
|
|
72
|
+
* ranked, still resolvable — it just stops asserting a match quality it does not have, which is what the FTS backend
|
|
73
|
+
* has always done and what every `exactMatch`-filtering consumer assumed.
|
|
74
|
+
*/
|
|
75
|
+
fuzzy?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The admin-containment verdict (#1717 stage 2), stamped by `candidate-lookup.ts` when the query carried a
|
|
78
|
+
* `regionQualifier` and the artifact carries the ancestors sidecar — the `fuzzy` precedent: a lookup-tier annotation
|
|
79
|
+
* declared on the shared row shape. Tri-state like `ResolvedPlace.containedByQualifier`: absent means the question
|
|
80
|
+
* was never asked, never "not contained".
|
|
81
|
+
*/
|
|
82
|
+
containedByQualifier?: boolean;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Bounded cross-country primary-name preference (see {@link PRIMARY_PREFERENCE_LOG10}). Pure + total-ordered so
|
|
86
|
+
* `candidate-lookup.test.ts` can exercise it on synthetic rows. `rows` arrive population-ordered (`neg_rank ASC`); an
|
|
87
|
+
* alias (`is_primary=0`) is pushed back by `delta` in log10-population units ONLY when the top-population primary
|
|
88
|
+
* sharing the key is in a different country, and is `demoted` out of the exact tier when that penalty leaves it BEHIND
|
|
89
|
+
* the primary. Returns the top `limit` after the re-rank, each annotated.
|
|
90
|
+
*
|
|
91
|
+
* `placetypes` (the artifact's own `placetype_codes` map) enables the LAST tiebreak, the SEAT preference: when
|
|
92
|
+
* `effectiveNegRank` and raw `neg_rank` both tie — two same-key rows population cannot separate at all — a
|
|
93
|
+
* {@link SEAT_PLACETYPE} row carrying a real population outranks every other placetype. Omit the map and every row
|
|
94
|
+
* scores 0, the term cancels, and the order is exactly the population-then-scan-order it was before.
|
|
95
|
+
*
|
|
96
|
+
* The tie it exists for is a DUPLICATE, not a contest. A district and its identically-named seat town are stored as two
|
|
97
|
+
* rows carrying the SAME population, so `neg_rank` is equal to the bit and `referential` follows it
|
|
98
|
+
* (`referentialFromPopulation` is a pure function of population). Turkey's `Of` is the measured case — locality
|
|
99
|
+
* 8114738869649 and its parent county 8837168432019 both hold population 44212 — and 358 locality/parent-county pairs
|
|
100
|
+
* across 15 countries share the shape in `admin-global-priority.db` (TR 162, CA 77, US 47, HR 24, DO 14). Without the
|
|
101
|
+
* term their order is whatever the scan hands the sorter.
|
|
102
|
+
*
|
|
103
|
+
* WHERE THE TERM DECIDES, AND WHERE IT CANNOT (#1729). It binds inside `findPlace`, so it orders every row set that
|
|
104
|
+
* actually CONTAINS the tie — but the resolver walk's probes all carry a placetype filter, and
|
|
105
|
+
* `PLACETYPE_FILTER_GROUPS` (core/resolver) never mixes `locality` with `county`: the `Of`-shape locality/county pair
|
|
106
|
+
* is PARTITIONED before this ranker runs, the locality probe fetches one row, and the walk's own `locality` request
|
|
107
|
+
* selects the seat by construction — the same winner, decided upstream. The tie that reaches an end-to-end answer
|
|
108
|
+
* through this term is the IN-GROUP residue: a locality/localadmin (or borough) duplicate whose `importance` values
|
|
109
|
+
* also tie. Downstream the resolver re-sorts by importance (`resolver/toponym-prior.ts`) but is stable on equal keys,
|
|
110
|
+
* so the order stamped here is the order that answers — inverting this term moves bare `Pu-cheng-hsien` 1,100 km
|
|
111
|
+
* (locality Pucheng over the 浦城县 localadmin, identical population and importance). Where importance separates the pair,
|
|
112
|
+
* the fame prior overrides by design; a probe with NO placetype filter (the browser cascade's last resort, the dev
|
|
113
|
+
* lookup tools) presents the full tie and this term is all that breaks it.
|
|
114
|
+
*
|
|
115
|
+
* BOTH GATES ARE LOAD-BEARING, and a plain "finer placetype wins" measured wrong before this shape was settled: it
|
|
116
|
+
* moved the top slot on 11,377 keys in `candidate.db`, of which only 722 were the seat/district duplicate. The rest
|
|
117
|
+
* were contests between genuinely distinct places that merely tie — 2,885 `locality → neighbourhood` (a bare city name
|
|
118
|
+
* losing to a same-named hood), 2,973 `region → county`, 2,662 `postalcode → locality` — and 7,179 of the 11,377 sat at
|
|
119
|
+
* population 0, where a tie means NO EVIDENCE rather than equal evidence. Requiring a real population keeps the term
|
|
120
|
+
* off every no-evidence tie; promoting the populated-place tier specifically, rather than whatever is finer, keeps it
|
|
121
|
+
* off the admin-tier and hood contests. It can never reach a pair population separates: it does not override a
|
|
122
|
+
* population gap, it replaces an undetermined order with a stated one.
|
|
123
|
+
*/
|
|
124
|
+
export declare function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(rows: readonly R[], limit: number, delta?: number, placetypes?: ReadonlyMap<number, string>, exemptVariantAliases?: boolean): Array<RankedRow<R>>;
|
|
125
|
+
//# sourceMappingURL=primary-preference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primary-preference.d.ts","sourceRoot":"","sources":["../primary-preference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,YAAY,CAAC,GACjF,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,CAAC,CAAC,CAAA;AAE1F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AASzC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,KAAK,CAAA;AAE9B;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG;IAC9B;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,CAAA;IACxB;;;;;;;OAOG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC9B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,oBAAoB,EACrE,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,SAA2B,EAChC,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACxC,oBAAoB,UAAQ,GAC1B,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CA+DrB"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Bounded cross-country PRIMARY-NAME preference over a population-ordered candidate row set — the
|
|
7
|
+
* `is_primary` ranking signal, PURE and platform-free so the Node candidate lookup
|
|
8
|
+
* (`candidate-lookup.ts`) and the browser twin (`docs/src/shared/httpvfs-resolver.ts`) rank with the
|
|
9
|
+
* SAME function rather than two copies that drift (the #861 server↔demo parity contract).
|
|
10
|
+
*
|
|
11
|
+
* Only type imports and arithmetic live here: anything with a `node:` import stays out.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Bounded PRIMARY-NAME preference across a CROSS-COUNTRY name collision (the `is_primary` ranking signal).
|
|
15
|
+
*
|
|
16
|
+
* The raw candidate order is population-first (`neg_rank ASC`) and treats an ALIAS row (a place's alt-name / exonym,
|
|
17
|
+
* `is_primary=0`) and a PRIMARY-name row (`is_primary=1`) on equal footing. So a foreign place whose transliterated
|
|
18
|
+
* exonym coincidentally normalizes to a query — Changchun CN stores the Turkish exonym "Çançun" (`name_key="cancun"`),
|
|
19
|
+
* 4.19 M pop — outranks the PRIMARY-name place the query actually means (Cancún MX, 0.89 M pop). This penalty makes a
|
|
20
|
+
* same-key alias have to clear a population MARGIN over a foreign primary before it wins.
|
|
21
|
+
*
|
|
22
|
+
* It is deliberately NOT a dominant sort key (no `ORDER BY is_primary DESC`, which would make every primary outrank
|
|
23
|
+
* every alias and break the alt-names users depend on — "NYC"→New York, "LA"→Los Angeles, "Frisco"→San Francisco). Two
|
|
24
|
+
* bounds keep it a soft prior:
|
|
25
|
+
*
|
|
26
|
+
* 1. **Cross-country only.** The penalty applies to an alias ONLY when the top-population primary sharing the key is in a
|
|
27
|
+
* DIFFERENT country. A SAME-country nickname contest (San Francisco's alias "Frisco" vs the primary Frisco, TX —
|
|
28
|
+
* both US) is left on pure population, so the legitimate alias still wins.
|
|
29
|
+
* 2. **Population-bounded.** The penalty is {@link PRIMARY_PREFERENCE_LOG10} in log10-population units — an alias must be
|
|
30
|
+
* at least 10x more populous than the foreign primary to still win. So a genuinely dominant alias keeps winning
|
|
31
|
+
* ("Los Angeles" over La, Ghana — gap 1.6; "Las Vegas" over Vegas, Cuba — gap 2.4) while a near-tie coincidental
|
|
32
|
+
* collision defers to the primary (Cancún over Changchun — gap 0.7).
|
|
33
|
+
*/
|
|
34
|
+
export const PRIMARY_PREFERENCE_LOG10 = 1;
|
|
35
|
+
/**
|
|
36
|
+
* The placetype the seat preference promotes: the populated-place tier a district duplicate shares its name and its
|
|
37
|
+
* population with. Named rather than inlined because narrowing the term to this ONE tier is what keeps it off the
|
|
38
|
+
* region/county and locality/neighbourhood contests — see `rankByPrimaryPreference` for the measurement.
|
|
39
|
+
*/
|
|
40
|
+
const SEAT_PLACETYPE = "locality";
|
|
41
|
+
/**
|
|
42
|
+
* Over-fetch cap for {@link rankByPrimaryPreference}: the candidate rows for one `name_key` (all same-name places
|
|
43
|
+
* worldwide) are re-ranked in-process, so the probe fetches this many (population-ordered) before the re-rank rather
|
|
44
|
+
* than the caller's small `limit`, ensuring the intended primary isn't cut below the fold by a cluster of more-populous
|
|
45
|
+
* foreign aliases. Bounded and small — a single contiguous B-tree scan.
|
|
46
|
+
*/
|
|
47
|
+
export const RERANK_FETCH = 64;
|
|
48
|
+
/**
|
|
49
|
+
* Bounded cross-country primary-name preference (see {@link PRIMARY_PREFERENCE_LOG10}). Pure + total-ordered so
|
|
50
|
+
* `candidate-lookup.test.ts` can exercise it on synthetic rows. `rows` arrive population-ordered (`neg_rank ASC`); an
|
|
51
|
+
* alias (`is_primary=0`) is pushed back by `delta` in log10-population units ONLY when the top-population primary
|
|
52
|
+
* sharing the key is in a different country, and is `demoted` out of the exact tier when that penalty leaves it BEHIND
|
|
53
|
+
* the primary. Returns the top `limit` after the re-rank, each annotated.
|
|
54
|
+
*
|
|
55
|
+
* `placetypes` (the artifact's own `placetype_codes` map) enables the LAST tiebreak, the SEAT preference: when
|
|
56
|
+
* `effectiveNegRank` and raw `neg_rank` both tie — two same-key rows population cannot separate at all — a
|
|
57
|
+
* {@link SEAT_PLACETYPE} row carrying a real population outranks every other placetype. Omit the map and every row
|
|
58
|
+
* scores 0, the term cancels, and the order is exactly the population-then-scan-order it was before.
|
|
59
|
+
*
|
|
60
|
+
* The tie it exists for is a DUPLICATE, not a contest. A district and its identically-named seat town are stored as two
|
|
61
|
+
* rows carrying the SAME population, so `neg_rank` is equal to the bit and `referential` follows it
|
|
62
|
+
* (`referentialFromPopulation` is a pure function of population). Turkey's `Of` is the measured case — locality
|
|
63
|
+
* 8114738869649 and its parent county 8837168432019 both hold population 44212 — and 358 locality/parent-county pairs
|
|
64
|
+
* across 15 countries share the shape in `admin-global-priority.db` (TR 162, CA 77, US 47, HR 24, DO 14). Without the
|
|
65
|
+
* term their order is whatever the scan hands the sorter.
|
|
66
|
+
*
|
|
67
|
+
* WHERE THE TERM DECIDES, AND WHERE IT CANNOT (#1729). It binds inside `findPlace`, so it orders every row set that
|
|
68
|
+
* actually CONTAINS the tie — but the resolver walk's probes all carry a placetype filter, and
|
|
69
|
+
* `PLACETYPE_FILTER_GROUPS` (core/resolver) never mixes `locality` with `county`: the `Of`-shape locality/county pair
|
|
70
|
+
* is PARTITIONED before this ranker runs, the locality probe fetches one row, and the walk's own `locality` request
|
|
71
|
+
* selects the seat by construction — the same winner, decided upstream. The tie that reaches an end-to-end answer
|
|
72
|
+
* through this term is the IN-GROUP residue: a locality/localadmin (or borough) duplicate whose `importance` values
|
|
73
|
+
* also tie. Downstream the resolver re-sorts by importance (`resolver/toponym-prior.ts`) but is stable on equal keys,
|
|
74
|
+
* so the order stamped here is the order that answers — inverting this term moves bare `Pu-cheng-hsien` 1,100 km
|
|
75
|
+
* (locality Pucheng over the 浦城县 localadmin, identical population and importance). Where importance separates the pair,
|
|
76
|
+
* the fame prior overrides by design; a probe with NO placetype filter (the browser cascade's last resort, the dev
|
|
77
|
+
* lookup tools) presents the full tie and this term is all that breaks it.
|
|
78
|
+
*
|
|
79
|
+
* BOTH GATES ARE LOAD-BEARING, and a plain "finer placetype wins" measured wrong before this shape was settled: it
|
|
80
|
+
* moved the top slot on 11,377 keys in `candidate.db`, of which only 722 were the seat/district duplicate. The rest
|
|
81
|
+
* were contests between genuinely distinct places that merely tie — 2,885 `locality → neighbourhood` (a bare city name
|
|
82
|
+
* losing to a same-named hood), 2,973 `region → county`, 2,662 `postalcode → locality` — and 7,179 of the 11,377 sat at
|
|
83
|
+
* population 0, where a tie means NO EVIDENCE rather than equal evidence. Requiring a real population keeps the term
|
|
84
|
+
* off every no-evidence tie; promoting the populated-place tier specifically, rather than whatever is finer, keeps it
|
|
85
|
+
* off the admin-tier and hood contests. It can never reach a pair population separates: it does not override a
|
|
86
|
+
* population gap, it replaces an undetermined order with a stated one.
|
|
87
|
+
*/
|
|
88
|
+
export function rankByPrimaryPreference(rows, limit, delta = PRIMARY_PREFERENCE_LOG10, placetypes, exemptVariantAliases = false) {
|
|
89
|
+
// The primary the alias actually competes with for the top slot: highest population (min neg_rank). Undefined
|
|
90
|
+
// when the set has no primary → nothing to prefer, penalty is 0, order stays population-first (today's behavior).
|
|
91
|
+
let topPrimary;
|
|
92
|
+
for (const r of rows) {
|
|
93
|
+
if (r.is_primary === 1 && (topPrimary == null || r.neg_rank < topPrimary.neg_rank)) {
|
|
94
|
+
topPrimary = r;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const topCountry = topPrimary?.country_id;
|
|
98
|
+
// A cross-country alias (different country than the top primary) is penalized; it is DEMOTED when even after — i.e.
|
|
99
|
+
// the penalty leaves its effective rank behind the primary's raw rank (it lost the bounded population contest).
|
|
100
|
+
//
|
|
101
|
+
// #1882 exemption (opt-in): a `name_role = 'variant'` alias is the holder's OWN primary name in another
|
|
102
|
+
// orthography (`Брэст` → `brest`, `George Town` → `georgetown` — the build's own-name detector), so the
|
|
103
|
+
// query is naming THAT place, not colliding with it; the penalty exists for the coincidental-collision
|
|
104
|
+
// class ("Çançun"/`cancun`), which the detector's measured threshold keeps un-stamped. An artifact
|
|
105
|
+
// predating the role column carries no 'variant' rows, so the flag no-ops there by construction.
|
|
106
|
+
const isCrossCountryAlias = (r) => typeof topCountry === "number" &&
|
|
107
|
+
r.is_primary !== 1 &&
|
|
108
|
+
r.country_id !== topCountry &&
|
|
109
|
+
!(exemptVariantAliases && r.name_role === "variant");
|
|
110
|
+
const annotate = (r) => {
|
|
111
|
+
const penalized = isCrossCountryAlias(r);
|
|
112
|
+
const effectiveNegRank = r.neg_rank + (penalized ? delta : 0);
|
|
113
|
+
return { ...r, effectiveNegRank, demoted: penalized && effectiveNegRank > topPrimary.neg_rank };
|
|
114
|
+
};
|
|
115
|
+
// 1 for a populated-place row that can BE a district's seat, 0 for everything else — no code map, no
|
|
116
|
+
// placetype on the row, an id the map does not carry, a placetype that is not the seat tier, or no
|
|
117
|
+
// recorded population. Every row scoring 0 cancels the term, leaving exactly the
|
|
118
|
+
// population-then-scan-order the sort had before it existed.
|
|
119
|
+
const seatPreference = (r) => placetypes != null &&
|
|
120
|
+
typeof r.placetype_id === "number" &&
|
|
121
|
+
typeof r.population === "number" &&
|
|
122
|
+
r.population > 0 &&
|
|
123
|
+
placetypes.get(r.placetype_id) === SEAT_PLACETYPE
|
|
124
|
+
? 1
|
|
125
|
+
: 0;
|
|
126
|
+
return (rows
|
|
127
|
+
.map((r, i) => ({ row: annotate(r), i }))
|
|
128
|
+
// Effective rank ASC; ties keep population order, then the seat preference DESC, then original
|
|
129
|
+
// index (stable).
|
|
130
|
+
// oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array; toSorted would double-allocate on a hot path
|
|
131
|
+
.sort((a, b) => a.row.effectiveNegRank - b.row.effectiveNegRank ||
|
|
132
|
+
a.row.neg_rank - b.row.neg_rank ||
|
|
133
|
+
seatPreference(b.row) - seatPreference(a.row) ||
|
|
134
|
+
a.i - b.i)
|
|
135
|
+
.slice(0, limit)
|
|
136
|
+
.map((x) => x.row));
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=primary-preference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primary-preference.js","sourceRoot":"","sources":["../primary-preference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAA;AAEzC;;;;GAIG;AACH,MAAM,cAAc,GAAG,UAAU,CAAA;AAEjC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAA;AAsC9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,uBAAuB,CACtC,IAAkB,EAClB,KAAa,EACb,KAAK,GAAG,wBAAwB,EAChC,UAAwC,EACxC,oBAAoB,GAAG,KAAK;IAE5B,8GAA8G;IAC9G,kHAAkH;IAClH,IAAI,UAAyB,CAAA;IAE7B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,CAAC,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpF,UAAU,GAAG,CAAC,CAAA;QACf,CAAC;IACF,CAAC;IAED,MAAM,UAAU,GAAG,UAAU,EAAE,UAAU,CAAA;IAEzC,oHAAoH;IACpH,gHAAgH;IAChH,EAAE;IACF,wGAAwG;IACxG,wGAAwG;IACxG,uGAAuG;IACvG,mGAAmG;IACnG,iGAAiG;IACjG,MAAM,mBAAmB,GAAG,CAAC,CAAI,EAAW,EAAE,CAC7C,OAAO,UAAU,KAAK,QAAQ;QAC9B,CAAC,CAAC,UAAU,KAAK,CAAC;QAClB,CAAC,CAAC,UAAU,KAAK,UAAU;QAC3B,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAA;IAErD,MAAM,QAAQ,GAAG,CAAC,CAAI,EAAgB,EAAE;QACvC,MAAM,SAAS,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAA;QACxC,MAAM,gBAAgB,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAE7D,OAAO,EAAE,GAAG,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE,SAAS,IAAI,gBAAgB,GAAG,UAAW,CAAC,QAAQ,EAAE,CAAA;IACjG,CAAC,CAAA;IAED,qGAAqG;IACrG,mGAAmG;IACnG,iFAAiF;IACjF,6DAA6D;IAC7D,MAAM,cAAc,GAAG,CAAC,CAAI,EAAU,EAAE,CACvC,UAAU,IAAI,IAAI;QAClB,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ;QAClC,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ;QAChC,CAAC,CAAC,UAAU,GAAG,CAAC;QAChB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,cAAc;QAChD,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,CAAC,CAAA;IAEL,OAAO,CACN,IAAI;SACF,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACzC,+FAA+F;QAC/F,kBAAkB;QAClB,8HAA8H;SAC7H,IAAI,CACJ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACR,CAAC,CAAC,GAAG,CAAC,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC,gBAAgB;QAC/C,CAAC,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ;QAC/B,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC;QAC7C,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CACV;SACA,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CACnB,CAAA;AACF,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* The proximity re-rank (#938): with bias hints — the demo's map viewport, a user location — re-order exact-match
|
|
7
|
+
* candidates by population and nearness on one additive scale, so an in-view namesake wins a tie without a hard
|
|
8
|
+
* filter. Byte-identical to plain population order when no bias is passed.
|
|
9
|
+
*
|
|
10
|
+
* This lives in its own platform-free module because it has to run identically in two places: the Node candidate
|
|
11
|
+
* reader and the browser byte-range twin. That is the #861 server↔demo parity contract, and it is the second thing
|
|
12
|
+
* here held by construction rather than by comment (`primary-preference.ts` was the first). Constants alone were not
|
|
13
|
+
* enough — the two copies agreed on every literal and still diverged on which field the population term reads and on
|
|
14
|
+
* whether the combined value is written back, which is the half that actually decides the answer.
|
|
15
|
+
*
|
|
16
|
+
* Two properties are load-bearing and easy to lose when transcribing:
|
|
17
|
+
*
|
|
18
|
+
* 1. The population base is `prominence ?? score`, NOT `score`. `prominence` carries the bounded cross-country
|
|
19
|
+
* primary preference, so reading raw score lets a coincidental foreign alias ride population back over a primary
|
|
20
|
+
* whenever a viewport hint happens to be present.
|
|
21
|
+
* 2. The combined value is PERSISTED into `prominence`. The resolver walk re-sorts by `prominence ?? score`, so a
|
|
22
|
+
* caller that only returns the array in bias order has its ordering silently discarded downstream.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Full magnitude of the nearness term at distance 0, before decay.
|
|
26
|
+
*/
|
|
27
|
+
export declare const BIAS_BOOST = 4;
|
|
28
|
+
/**
|
|
29
|
+
* Full magnitude of the population term, reached at {@link POP_SCALE_LOG10} and capped there.
|
|
30
|
+
*/
|
|
31
|
+
export declare const POP_BOOST = 4;
|
|
32
|
+
/**
|
|
33
|
+
* `log10(population + 1)` at which the population term saturates — 6 means a population of one million earns the whole
|
|
34
|
+
* {@link POP_BOOST}, and larger populations earn no more.
|
|
35
|
+
*/
|
|
36
|
+
export declare const POP_SCALE_LOG10 = 6;
|
|
37
|
+
/**
|
|
38
|
+
* Distance at which the nearness term halves.
|
|
39
|
+
*
|
|
40
|
+
* SHARPER than the FTS reader's 100 km on purpose: the candidate backend's score is log-population ALONE, with no bm25
|
|
41
|
+
* document term, so the population signal is weaker relative to the bias and a gentle 100 km decay let a 230 km-distant
|
|
42
|
+
* alias-exact township ("Paris Township", OH) edge out a global city ("Paris", FR) from a nearby view. At ~30 km the
|
|
43
|
+
* boost reaches only candidates the user is actually looking at: an in-view namesake still wins (Dublin, OH from an
|
|
44
|
+
* Ohio view), a distant one no longer does (Paris stays FR from a Michigan view).
|
|
45
|
+
*/
|
|
46
|
+
export declare const PROX_SCALE_KM = 30;
|
|
47
|
+
/**
|
|
48
|
+
* One bias hint — a coordinate the user is looking at or standing on, optionally weighted.
|
|
49
|
+
*/
|
|
50
|
+
export interface ProximityBias {
|
|
51
|
+
lat: number;
|
|
52
|
+
lon: number;
|
|
53
|
+
weight?: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The candidate fields the re-rank reads and writes. Structural rather than a concrete candidate type, so the Node
|
|
57
|
+
* reader's `PlaceCandidate` and the browser twin's row shape both satisfy it without an adapter.
|
|
58
|
+
*/
|
|
59
|
+
export interface ProximityRerankable {
|
|
60
|
+
lat: number;
|
|
61
|
+
lon: number;
|
|
62
|
+
score: number;
|
|
63
|
+
prominence?: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Population plus nearness on one additive scale. Exported for tests and for a caller that wants the value without the
|
|
67
|
+
* sort; ordinary callers want {@link applyProximityRerank}.
|
|
68
|
+
*/
|
|
69
|
+
export declare function combinedProminence(candidate: ProximityRerankable, bias: readonly ProximityBias[]): number;
|
|
70
|
+
/**
|
|
71
|
+
* Re-order `candidates` in place by {@link combinedProminence}, persisting each combined value into `prominence` so the
|
|
72
|
+
* resolver walk's own `prominence ?? score` sort carries the bias order rather than undoing it. Stable within equal
|
|
73
|
+
* prominence, preserving the population order the index already gave. A caller with no bias hints must not call this —
|
|
74
|
+
* the no-bias path is plain population order by construction.
|
|
75
|
+
*/
|
|
76
|
+
export declare function applyProximityRerank<T extends ProximityRerankable>(candidates: T[], bias: readonly ProximityBias[]): T[];
|
|
77
|
+
//# sourceMappingURL=proximity-rerank.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proximity-rerank.d.ts","sourceRoot":"","sources":["../proximity-rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH;;GAEG;AACH,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;GAEG;AACH,eAAO,MAAM,SAAS,IAAI,CAAA;AAE1B;;;GAGG;AACH,eAAO,MAAM,eAAe,IAAI,CAAA;AAEhC;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,KAAK,CAAA;AAE/B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAmBzG;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,mBAAmB,EACjE,UAAU,EAAE,CAAC,EAAE,EACf,IAAI,EAAE,SAAS,aAAa,EAAE,GAC5B,CAAC,EAAE,CAYL"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* The proximity re-rank (#938): with bias hints — the demo's map viewport, a user location — re-order exact-match
|
|
7
|
+
* candidates by population and nearness on one additive scale, so an in-view namesake wins a tie without a hard
|
|
8
|
+
* filter. Byte-identical to plain population order when no bias is passed.
|
|
9
|
+
*
|
|
10
|
+
* This lives in its own platform-free module because it has to run identically in two places: the Node candidate
|
|
11
|
+
* reader and the browser byte-range twin. That is the #861 server↔demo parity contract, and it is the second thing
|
|
12
|
+
* here held by construction rather than by comment (`primary-preference.ts` was the first). Constants alone were not
|
|
13
|
+
* enough — the two copies agreed on every literal and still diverged on which field the population term reads and on
|
|
14
|
+
* whether the combined value is written back, which is the half that actually decides the answer.
|
|
15
|
+
*
|
|
16
|
+
* Two properties are load-bearing and easy to lose when transcribing:
|
|
17
|
+
*
|
|
18
|
+
* 1. The population base is `prominence ?? score`, NOT `score`. `prominence` carries the bounded cross-country
|
|
19
|
+
* primary preference, so reading raw score lets a coincidental foreign alias ride population back over a primary
|
|
20
|
+
* whenever a viewport hint happens to be present.
|
|
21
|
+
* 2. The combined value is PERSISTED into `prominence`. The resolver walk re-sorts by `prominence ?? score`, so a
|
|
22
|
+
* caller that only returns the array in bias order has its ordering silently discarded downstream.
|
|
23
|
+
*/
|
|
24
|
+
import { haversineKm } from "@mailwoman/spatial";
|
|
25
|
+
/**
|
|
26
|
+
* Full magnitude of the nearness term at distance 0, before decay.
|
|
27
|
+
*/
|
|
28
|
+
export const BIAS_BOOST = 4;
|
|
29
|
+
/**
|
|
30
|
+
* Full magnitude of the population term, reached at {@link POP_SCALE_LOG10} and capped there.
|
|
31
|
+
*/
|
|
32
|
+
export const POP_BOOST = 4;
|
|
33
|
+
/**
|
|
34
|
+
* `log10(population + 1)` at which the population term saturates — 6 means a population of one million earns the whole
|
|
35
|
+
* {@link POP_BOOST}, and larger populations earn no more.
|
|
36
|
+
*/
|
|
37
|
+
export const POP_SCALE_LOG10 = 6;
|
|
38
|
+
/**
|
|
39
|
+
* Distance at which the nearness term halves.
|
|
40
|
+
*
|
|
41
|
+
* SHARPER than the FTS reader's 100 km on purpose: the candidate backend's score is log-population ALONE, with no bm25
|
|
42
|
+
* document term, so the population signal is weaker relative to the bias and a gentle 100 km decay let a 230 km-distant
|
|
43
|
+
* alias-exact township ("Paris Township", OH) edge out a global city ("Paris", FR) from a nearby view. At ~30 km the
|
|
44
|
+
* boost reaches only candidates the user is actually looking at: an in-view namesake still wins (Dublin, OH from an
|
|
45
|
+
* Ohio view), a distant one no longer does (Paris stays FR from a Michigan view).
|
|
46
|
+
*/
|
|
47
|
+
export const PROX_SCALE_KM = 30;
|
|
48
|
+
/**
|
|
49
|
+
* Population plus nearness on one additive scale. Exported for tests and for a caller that wants the value without the
|
|
50
|
+
* sort; ordinary callers want {@link applyProximityRerank}.
|
|
51
|
+
*/
|
|
52
|
+
export function combinedProminence(candidate, bias) {
|
|
53
|
+
const popBase = candidate.prominence ?? candidate.score;
|
|
54
|
+
const popTerm = POP_BOOST * Math.min(1, Math.max(0, popBase) / POP_SCALE_LOG10);
|
|
55
|
+
let proxTerm = 0;
|
|
56
|
+
// A candidate at the null island has no coordinate, not a coordinate at 0,0 — it earns no nearness term rather
|
|
57
|
+
// than an enormous one.
|
|
58
|
+
if (!(candidate.lat === 0 && candidate.lon === 0)) {
|
|
59
|
+
for (const b of bias) {
|
|
60
|
+
const d = haversineKm(b.lat, b.lon, candidate.lat, candidate.lon);
|
|
61
|
+
const term = (BIAS_BOOST * (b.weight ?? 1)) / (1 + d / PROX_SCALE_KM);
|
|
62
|
+
if (term > proxTerm) {
|
|
63
|
+
proxTerm = term;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return popTerm + proxTerm;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Re-order `candidates` in place by {@link combinedProminence}, persisting each combined value into `prominence` so the
|
|
71
|
+
* resolver walk's own `prominence ?? score` sort carries the bias order rather than undoing it. Stable within equal
|
|
72
|
+
* prominence, preserving the population order the index already gave. A caller with no bias hints must not call this —
|
|
73
|
+
* the no-bias path is plain population order by construction.
|
|
74
|
+
*/
|
|
75
|
+
export function applyProximityRerank(candidates, bias) {
|
|
76
|
+
candidates
|
|
77
|
+
.map((c, i) => {
|
|
78
|
+
c.prominence = combinedProminence(c, bias);
|
|
79
|
+
return { c, i, p: c.prominence };
|
|
80
|
+
})
|
|
81
|
+
// oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array; toSorted would double-allocate on a hot path
|
|
82
|
+
.sort((a, b) => b.p - a.p || a.i - b.i)
|
|
83
|
+
.forEach((x, j) => (candidates[j] = x.c));
|
|
84
|
+
return candidates;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=proximity-rerank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proximity-rerank.js","sourceRoot":"","sources":["../proximity-rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAA;AAE3B;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAA;AAE1B;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAA;AAEhC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAA;AAsB/B;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAA8B,EAAE,IAA8B;IAChG,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,IAAI,SAAS,CAAC,KAAK,CAAA;IACvD,MAAM,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,eAAe,CAAC,CAAA;IAC/E,IAAI,QAAQ,GAAG,CAAC,CAAA;IAEhB,+GAA+G;IAC/G,wBAAwB;IACxB,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,IAAI,SAAS,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;YACjE,MAAM,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAA;YAErE,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;gBACrB,QAAQ,GAAG,IAAI,CAAA;YAChB,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,OAAO,GAAG,QAAQ,CAAA;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CACnC,UAAe,EACf,IAA8B;IAE9B,UAAU;SACR,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACb,CAAC,CAAC,UAAU,GAAG,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QAE1C,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE,CAAA;IACjC,CAAC,CAAC;QACF,8HAA8H;SAC7H,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SACtC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAE1C,OAAO,UAAU,CAAA;AAClB,CAAC"}
|