Skip to main content

Locate Search

This guide explains how to configure locate-search.xml for business needs: what each field means, allowed values, and which setup to choose for common use cases.

What You Configure

You configure one or more providers in locate-search.xml. Each provider is one searchable source (for example: addresses, parcels, water assets, organizational units).

At runtime, the system queries all configured providers and merges the results.


1) Provider Blueprint

Use this as the base shape for each provider:

<ber:locateSearchProvider
id="your_provider_id"
type="rest"
providerType="geojson|lidsElastic"
name="Visible provider name"
order="1"
defaultColor="#00FF00"
defaultIcon="info"
coordinatesOrder="xy|yx">

<ber:locateSearchCategoryArray>
<ber:locateSearchCategory id="category_id" name="Category label" color="#ABCDEF" icon="ic_example"/>
</ber:locateSearchCategoryArray>

<ber:commonRestInputConfiguration method="GET|POST" removeBlanks="true|false">
<ber:url>...</ber:url>
<ber:requestBody>...</ber:requestBody>
<ber:replaceBlanks>+</ber:replaceBlanks>
</ber:commonRestInputConfiguration>

<ber:categorySource type="property" name="origin"/>

<ber:responseForm>
<ber:name>label</ber:name>
</ber:responseForm>
</ber:locateSearchProvider>

2) Field Reference (Allowed Values + Meaning)

A. Provider-level fields

FieldRequiredAllowed valuesBusiness meaning
idyesany unique text (e.g. swtopo_address, lids_water)Internal unique key of the provider
typeyesrestKeep fixed to rest
providerTypeyesgeojson, lidsElasticSource type: external GeoJSON API vs LIDS Elasticsearch
nameyesany textProvider label users see in results
orderyesinteger (1, 2, 3, ...)Display priority (lower number = higher priority)
defaultColornohex color (e.g. #00FF00)Fallback color when category has no color
defaultIconnoicon key used in your client setupFallback icon when category has no icon
coordinatesOrdernoxy or yxCoordinate interpretation for GeoJSON geometry; use yx for many external map APIs

B. Category mapping fields

FieldRequiredAllowed valuesBusiness meaning
locateSearchCategory[@id]yessource category key (e.g. district, ft_5010100)Category identifier coming from search source
locateSearchCategory[@name]noany textUser-friendly category label
locateSearchCategory[@color]nohex colorCategory-specific color
locateSearchCategory[@icon]noicon keyCategory-specific icon

C. Request fields (commonRestInputConfiguration)

FieldRequiredAllowed valuesBusiness meaning
methodyesGET, POSTHow to call the source
urlyesURL/path textEndpoint to call. Use %%SEARCH_PHRASE%% placeholder for user input
requestBodyPOST scenariosJSON textBody for POST search requests
removeBlanksnotrue, falseIf true, spaces are removed from search text
replaceBlanksnoany replacement string (+, %20, etc.)Replace spaces with a specific character/string

Important rule: do not use both removeBlanks="true" and <ber:replaceBlanks>...</ber:replaceBlanks> in the same provider.

D. Additional fields

FieldRequiredAllowed valuesBusiness meaning
categorySource[@type]for geojsonpropertyCategory comes from a property in response
categorySource[@name]for geojsonproperty key (e.g. origin)Which property contains category id
responseForm/namerecommendedproperty/field name (label, featureInfo, etc.)Which field is shown as main result text

3) Which Provider Type Should You Use?

Choose providerType="geojson" when:

  • You search data from an external API returning GeoJSON.
  • You can pass user text in URL query parameters.
  • Categories are provided in response properties (e.g. origin).

Typical examples: addresses, districts, municipalities, parcels from public map APIs.

Choose providerType="lidsElastic" when:

  • You search internal LIDS business data indexed in Elasticsearch.
  • You need structured POST JSON query (types, query, size, optional geometries).
  • Category is based on your internal feature types (e.g. ft_5010100).

Typical examples: utility assets, internal parcel layers, organization-specific entities.


4) lidsElastic requestBody Reference

The requestBody is a JSON object passed directly to /rest/search/features. All fields:

{
"types": ["ft_5010100", "ft_5012100", "ft_parcel_area"],
"query": { ... },
"size": 20,
"from": 0,
"geometries": ["ft_parcel_face"],
"typeQuery": { "ft_5010100": { ... } },
"interfaceQuery": { "<key>": { ... } },
"interfaceOperator": "AND",
"relationsFilter": { "<relatedType>": ["<relatedFeatureId>"] },
"typeRelationsFilter": { "<searchedType>": { "<relatedType>": ["<relatedId>"] } }
}
FieldRequiredDescription
typesyesFeature type IDs to search. Only semantic parent types for shared semantics (see sharedSemantics below).
queryyesQuery condition applied across all types. Use %%SEARCH_PHRASE%% as placeholder.
sizenoMax results to return (default: 10).
fromnoOffset for pagination. Note: totalHits is capped to from + size.
geometriesnoFilter returned geometries for shared semantics by feature type ID, e.g. ["ft_parcel_face"]. Omit to return all geometry types.
typeQuerynoPer-feature-type query condition (key = feature type ID). Combined with query via AND.
interfaceQuerynoCross-type condition using interface attributes (key = arbitrary string).
interfaceOperatorno"AND" (default) or "OR" — how typeQuery / interfaceQuery combine.
relationsFilternoFilter by related features across all types.
typeRelationsFilternoPer-type relation filter.

Query condition types

Every query condition has at least a type field. Use %%SEARCH_PHRASE%% for user input:

typeAdditional fieldsNotes
matchPhrasePrefixfield, value, operatorRecommended for locate-search. Prefix-matches user input on text fields. "field": "all" searches all indexed text attributes at once.
wildcardfield, queryPattern with * / ?. Use .keyword suffix on the field name (e.g. "at_5120002.keyword"). %%SEARCH_PHRASE%%* is a typical pattern.
matchfield, query, operatorFull-text match. Operator: "and" or "or".
matchPhrasefield, queryExact phrase match.
matchAllMatches all indexed documents.
termsfield, valuesExact match against a list of values. Use .keyword suffix.
rangefield, from, to, includeUpper, includeLowerNumeric or date range.
existsfieldMatches documents where the field is present.
boolmust, should, must_notCompound query. Each is a list of nested conditions.
disMaxqueriesDisjunction-max across a list of sub-queries (highest-scoring clause wins).
geoShapefield, shapeType, shapeCoordinates, relation, srsSpatial filter against the geometry stored in Elasticsearch. relation: intersects, within, contains, disjoint.

The special "field": "all" value searches across all indexed text attributes simultaneously — it is the most common choice for locate-search.

Examples:

// matchPhrasePrefix — typical locate-search query
{"type": "matchPhrasePrefix", "field": "all", "operator": "and", "query": "%%SEARCH_PHRASE%%"}

// wildcard — suffix wildcard on a specific keyword attribute
{"type": "wildcard", "field": "at_5120002.keyword", "query": "%%SEARCH_PHRASE%%*"}

// bool — combine must + should
{
"type": "bool",
"must": [{"type": "matchPhrasePrefix", "field": "all", "query": "%%SEARCH_PHRASE%%"}],
"should": [{"type": "terms", "field": "at_5010001.keyword", "values": ["active"]}]
}

Geometry and sharedSemantics

sharedSemantics is a LIDS metadata concept where multiple graphical child feature types share the attributes of a semantic parent type but carry their own geometry. Examples: a parcel (semantic parent) with a centroid symbol (child type, Point) and a polygon (child type, Surface).

Consequences for locate-search configuration:

  • Only semantic parent types can appear in "types". Child shared-semantics types are indexed under the parent's type ID. Including a child type ID directly will return no results.
  • Multiple geometries per document. When a semantic type has shared-semantics children, Elasticsearch stores all geometries (one per child) in the "geometries" array of the indexed document.
  • locate-search creates one result per geometry. Because LidsElasticProviderStrategy iterates the "geometries" array, a single feature can produce multiple locate-search hits — one for each stored geometry.
  • Restrict geometry types with "geometries". To avoid duplicate hits or unwanted geometry types, add "geometries": ["ft_parcel_face"] (feature type IDs from metadata) to the requestBody. Only geometries whose geometryTypeId matches are returned; hits with no matching geometry are dropped entirely.
  • Geo-shape spatial filter (geoShape query) operates on search_geometry, which is the merged GeometryCollection of all geometries for the feature — it covers all child geometries in one go.

Example: semantic parent type ft_parcel_area has two shared-semantics children: ft_parcel_face carrying its polygon geometry and ft_parcel_point carrying its centroid geometry. To return only the face geometry (and avoid duplicate hits):

{
"types": ["ft_parcel_area"],
"query": {"type": "matchPhrasePrefix", "field": "all", "operator": "and", "query": "%%SEARCH_PHRASE%%"},
"size": 20,
"geometries": ["ft_parcel_face"]
}

5) Ready-to-Use Configuration Recipes

Recipe A - External address search (GeoJSON)

Use when users search addresses from external source.

<ber:locateSearchProvider id="swtopo_address" type="rest" providerType="geojson"
name="Swisstopo addresses" order="3" defaultColor="#db9909" defaultIcon="ic_adresse" coordinatesOrder="yx">
<ber:locateSearchCategoryArray>
<ber:locateSearchCategory id="address" name="Address" color="#db9909" icon="ic_adresse"/>
</ber:locateSearchCategoryArray>
<ber:commonRestInputConfiguration method="GET" removeBlanks="true">
<ber:url>https://api3.geo.admin.ch/rest/services/api/SearchServer?searchText=%%SEARCH_PHRASE%%&amp;origins=address&amp;type=locations&amp;sr=4326&amp;limit=10&amp;geometryFormat=geojson</ber:url>
</ber:commonRestInputConfiguration>
<ber:categorySource type="property" name="origin"/>
<ber:responseForm><ber:name>label</ber:name></ber:responseForm>
</ber:locateSearchProvider>

Business tips:

  • Keep order lower if addresses must appear near top.
  • removeBlanks="true" is useful if the API expects compact address search terms.

Recipe B - External parcel/administrative search (GeoJSON)

Use when one provider should return multiple public categories.

<ber:locateSearchProvider id="swtopo_parcel" type="rest" providerType="geojson"
name="Swisstopo parcels" order="1" defaultColor="#db09cd" defaultIcon="info" coordinatesOrder="yx">
<ber:locateSearchCategoryArray>
<ber:locateSearchCategory id="gg25" name="Municipality" color="#db09cd" icon="ic_gemeinde"/>
<ber:locateSearchCategory id="parcel" name="Parcel" color="#33db09" icon="ic_parzelle"/>
</ber:locateSearchCategoryArray>
<ber:commonRestInputConfiguration method="GET">
<ber:url>https://api3.geo.admin.ch/rest/services/api/SearchServer?searchText=%%SEARCH_PHRASE%%&amp;origins=gg25,parcel&amp;type=locations&amp;sr=4326&amp;limit=10&amp;geometryFormat=geojson</ber:url>
</ber:commonRestInputConfiguration>
<ber:categorySource type="property" name="origin"/>
<ber:responseForm><ber:name>label</ber:name></ber:responseForm>
</ber:locateSearchProvider>

Business tips:

  • Categories let you brand each result type with distinct icon/color.
  • This is ideal when a single API returns mixed object families.

Recipe C1 - Multiple LIDS feature types, no shared semantics

Use when searching across several independent feature types (each has its own geometry, no shared-semantics children).

<ber:locateSearchProvider id="lids_water" type="rest" providerType="lidsElastic"
name="LIDS water" order="5" defaultColor="#0000FF" defaultIcon="ic_demo">
<ber:locateSearchCategoryArray>
<ber:locateSearchCategory id="ft_5010100" name="Pumping Station" icon="ic_5010100"/>
<ber:locateSearchCategory id="ft_5012100" name="Main Pipeline Segment" color="#0abab5" icon="ic_5012100"/>
</ber:locateSearchCategoryArray>
<ber:commonRestInputConfiguration method="POST">
<ber:url>/rest/search/features</ber:url>
<ber:requestBody>
{
"types": ["ft_5010100", "ft_5012100"],
"query": {
"type": "matchPhrasePrefix",
"field": "all",
"operator": "and",
"query": "%%SEARCH_PHRASE%%"
},
"size": 20
}
</ber:requestBody>
</ber:commonRestInputConfiguration>
<ber:responseForm><ber:name>featureInfo</ber:name></ber:responseForm>
</ber:locateSearchProvider>

Business tips:

  • List all relevant feature type IDs in types. Each type appears as a separate category in results.
  • No geometries filter needed — each feature has exactly one geometry.

Recipe C2 - Single LIDS feature type with shared semantics

Use when the semantic parent type (ft_parcel_area) has a shared-semantics child type (ft_parcel_face) that carries its own geometry. Without filtering, locate-search would return one hit per geometry (i.e. duplicate hits). Use "geometries" to keep only the desired geometry type.

<ber:locateSearchProvider id="lids_orgunit" type="rest" providerType="lidsElastic"
name="LIDS parcel" order="4" defaultColor="#00FF00" defaultIcon="ic_demo">
<ber:locateSearchCategoryArray>
<ber:locateSearchCategory id="ft_parcel_area" name="Parcel area" icon="ic_5060000"/>
</ber:locateSearchCategoryArray>
<ber:commonRestInputConfiguration method="POST">
<ber:url>/rest/search/features</ber:url>
<ber:requestBody>
{
"types": ["ft_parcel_area"],
"query": {
"type": "matchPhrasePrefix",
"field": "all",
"operator": "and",
"query": "%%SEARCH_PHRASE%%"
},
"geometries": ["ft_parcel_face"],
"size": 20
}
</ber:requestBody>
</ber:commonRestInputConfiguration>
<ber:responseForm><ber:name>featureInfo</ber:name></ber:responseForm>
</ber:locateSearchProvider>

Business tips:

  • types contains only the shared semantics parents — shared-semantics child types cannot be searched directly.
  • geometries lists the child feature type ID whose geometry you want to show on the map. Omitting it would produce one locate-search hit per stored geometry (i.e. duplicate hits for each feature).
  • The category ID in locateSearchCategoryArray should match the semantic parent type ID (ft_parcel_area), since that is what the search result carries as its type.

5) Business Decision Rules

  • Priority of providers: control with order; smaller number means higher visibility priority.
  • User-facing naming: use meaningful name and category name values (business terms, not technical IDs).
  • Branding consistency: define both provider defaults and category-specific overrides.
  • Search phrase handling:
    • removeBlanks="true" for sources that fail on spaces.
    • replaceBlanks for sources expecting + or custom separator.
    • otherwise keep default encoding behavior.
  • Coordinate order: if map markers appear in wrong location, switch coordinatesOrder between xy and yx.

6) Minimum Safe Checklist Before Go-Live

  • Every provider has unique id.
  • providerType and method match the use case:
    • GeoJSON -> usually GET
    • LIDS Elastic -> POST + /rest/search/features
  • url (and requestBody for POST) includes %%SEARCH_PHRASE%% where user text should go.
  • All expected source categories are mapped in locateSearchCategoryArray.
  • responseForm/name points to a field that actually exists in response (label, featureInfo, etc.).
  • Colors/icons are set (at least provider defaults).
  • For GeoJSON, categorySource type="property" name="..." matches real response property.
  • Coordinates display correctly on map (coordinatesOrder).

7) Common Mistakes to Avoid

  • Using providerType="lidsElastic" with method="GET".
  • Forgetting %%SEARCH_PHRASE%%, causing static or empty search behavior.
  • Category IDs not matching source values (results appear without expected labels/icons).
  • Omitting fallback defaultColor and defaultIcon, causing inconsistent UI.
  • Setting both removeBlanks and replaceBlanks in same provider.

8) Quick Starter Template (Copy, Then Adjust)

<ber:locateSearchProvider id="my_provider" type="rest" providerType="geojson"
name="My Provider" order="1" defaultColor="#3A7AFE" defaultIcon="info" coordinatesOrder="yx">
<ber:locateSearchCategoryArray>
<ber:locateSearchCategory id="cat1" name="Category 1" color="#3A7AFE" icon="ic_cat1"/>
</ber:locateSearchCategoryArray>
<ber:commonRestInputConfiguration method="GET">
<ber:url>https://example.org/search?q=%%SEARCH_PHRASE%%&amp;geometryFormat=geojson</ber:url>
</ber:commonRestInputConfiguration>
<ber:categorySource type="property" name="origin"/>
<ber:responseForm><ber:name>label</ber:name></ber:responseForm>
</ber:locateSearchProvider>

If you are configuring internal LIDS Elasticsearch instead, switch to:

  • providerType="lidsElastic"
  • method="POST"
  • url -> /rest/search/features
  • add JSON <ber:requestBody> with your types and query.