Skip to content
Developers Docs

Combination (Cross-Reference) Search

Combination search lets a single query combine a container — a building or a category — with one or more entity terms scoped inside it. A search for business 101 finds unit 101 inside the Business Center; coffee shop finds shops tagged Coffee. It runs as an additive layer on top of the standard unified search, surfacing "results inside a container" alongside the normal results.

Availability

New in iOS SDK 26.7.1. Combination search is part of unified (General) search and is on by default. The feature flags are on MapUICustomParams (import MapstedMapUi); the underlying matcher CombinationSearchMatcher is public in MapstedCore for advanced use.

Enabling and disabling

Combination search is enabled by default whenever unified search is active. You can toggle either flag:

import MapstedMapUi

// Both are true by default.
MapUICustomParams.shared.unifiedSearchEnabled = true       // the General (unified) search
MapUICustomParams.shared.combinationSearchEnabled = true   // the combination/cross-reference layer

Android: combination search is applied automatically by the Android search subsystem; there is no separate enable/disable flag. For custom search UIs, use the matcher directly (below).

Set combinationSearchEnabled = false to keep unified search but drop the combination layer.

How a query is interpreted

The matcher tokenizes the query, decides which tokens identify a container, and leaves the rest as entity terms scoped to that container:

  • business 101 → container business (matches the Business Center building) + entity token 101 → units named/keyed 101 inside that building.
  • coffee shop → container coffee (matches the Coffee category) + entity token shop → POIs tagged Coffee whose name or keywords contain shop.

Container matching is generic — there is no maintained keyword list. Numeric tokens (like 101) are never treated as a container, and a container only engages when a query token distinctively matches one of its name words.

There is no SearchScope type

Search scoping is expressed by the SearchInSection enum (.General, .Buildings, .POI, .Categories, .Tags, .MapOverlayItems). Combination search runs in the .General (unified) scope. There is no SearchScope enum or .GENERAL constant.

Advanced: using the matcher directly

For custom search UIs you can call the pure, UI-free CombinationSearchMatcher yourself. Build a Candidate per container (its key is any type you choose — a building id, a category name), then match a query against them. Each Match gives you the container's key, a score, a coverage fraction, and the residual entityTokens to apply to your entity-scoped search.

import com.mapsted.positioning.coreObjects.CombinationSearchMatcher;
import java.util.*;

// Build candidates (key + tokenized name words), then match a query.
List<CombinationSearchMatcher.Candidate<Integer>> candidates = new ArrayList<>();
candidates.add(new CombinationSearchMatcher.Candidate<>(101, Arrays.asList("nike", "store")));

List<CombinationSearchMatcher.Match<Integer>> matches =
        CombinationSearchMatcher.match("nike shoes", candidates);

for (CombinationSearchMatcher.Match<Integer> m : matches) {
    Integer key      = m.getKey();
    double  score    = m.getScore();
    double  coverage = m.getCoverage();
}

// Low-level tokenizer, if you need it:
List<CombinationSearchMatcher.Token> tokens = CombinationSearchMatcher.tokenize("nike shoes");
import MapstedCore

// Describe the containers you want to match against.
let candidates = [
    CombinationSearchMatcher.Candidate(key: 101, nameWords: ["business", "center"]),
    CombinationSearchMatcher.Candidate(key: 102, nameWords: ["medical", "center"]),
]

// Match a query. Results are ordered by score, then coverage.
let matches = CombinationSearchMatcher.match("business 101", candidates)
for match in matches {
    print("container \(match.key): score=\(match.score), coverage=\(match.coverage)")
    print("apply these entity tokens inside it: \(match.entityTokens)")   // ["101"]
}

// You can also tokenize a query yourself.
let tokens = CombinationSearchMatcher.tokenize("business center")         // [business, center]

Candidate is generic over its key type (Candidate<K>), so use Int keys for buildings, String keys for categories, or whatever identifies your containers.

Tips & Considerations

  • Numeric tokens never match a container. 101 is always an entity term, never a building/category — by design.
  • A container needs a distinctive match. A query engages a container only when at least one token matches a non-generic word of its name, so shared words like "Center" across many tenants do not cause false matches.
  • match returns containers ordered by score then coverage. Apply the entityTokens of each match to your entity search to produce the scoped results.
  • The high-level combination display is part of unified search. Toggle it with MapUICustomParams.shared.combinationSearchEnabled; use CombinationSearchMatcher directly only when you build your own search UI.