Data providers
The Mapbox Search SDK for Android is in public beta. All features and workflows are subject to change.
The Mapbox Search SDK for Android lets developers to attach their own places, POIs, and address information to SearchEngine
via data providers. Engines will index the provided data and use this data during forward geocoding and category search requests.
Indexable record
IndexableRecord
stores place, POI, and address information that can later be used by both users and the Search SDK. The Search SDK uses information from IndexableRecord
to prepare the data provider engine and construct search results.
You can retrieve IndexableRecord
from SearchResult.indexableRecord
, which is non null if SearchResult
has been constructed from IndexableRecord
:
val searchResult: SearchResult = // ...
val record = searchResult?.indexableRecord
Data provider
IndexableDataProvider
has two main responsibilities:
- Store
IndexableRecords
and provide read and write access so the Search SDK is able to retrieve and add records. - Keep the data provider engine up to date to guarantee all indexable records are available during search.
Each indexable record has an associated priority that helps search engines determine the ranking of search results constructed from indexable records. The priority of a record is equal to the priority of the data provider which is determined by IndexableDataProvider.priority
property.
Data provider engine
IndexableDataProviderEngine
is a search index that can be used by multiple search engines during search requests after processing. If you want search engines to be able to search across your data, add all necessary indexable records to the engine during the IndexableDataProvider.registerIndexableDataProviderEngine()
operation or later, when data will become available:
class CustomDataProvider : IndexableDataProvider<CustomIndexableRecord> {
private val dataProviderEngines: MutableList<IndexableDataProviderEngine> = mutableListOf()
private val records: MutableList<IndexableRecord> = mutableListOf()
/**
* Invoked when `CustomDataProvider` is registered in a `SearchEngine`.
*/
override fun registerIndexableDataProviderEngine(
dataProviderEngine: IndexableDataProviderEngine,
executor: Executor,
callback: CompletionCallback<Unit>
): AsyncOperationTask {
synchronized(this) {
dataProviderEngines.add(dataProviderEngine)
dataProviderEngine.upsertAll(records)
}
executor.execute {
callback.onComplete(Unit)
}
return CompletedAsyncOperationTask
}
/**
* Invoked when search records become available.
*/
private fun onDataLoaded(customData: List<CustomIndexableRecord>) {
synchronized(this) {
records.addAll(customData)
dataProviderEngines.forEach { engine ->
engine.upsertAll(records)
}
}
}
// ...
private object CompletedAsyncOperationTask : AsyncOperationTask {
override val isDone: Boolean
get() = true
override val isCancelled: Boolean
get() = false
override fun cancel() {
// Do nothing
}
}
}
IndexableDataProviderEngine
is thread-safe and can be called from different threads.
Even though in most cases changing the index used in the data provider engine takes a few milliseconds, sometimes it may take longer for operation to complete (for example, when the data provider engine is used by a search engine or when user adds more than 10,000 records).
Built-in data providers
The Mapbox Search SDK for Android has built-in data providers that are already attached to each instance of SearchEngine
and CategorySearchEngine
.
Favorites Data Provider
The main purpose of FavoritesDataProvider
is to store each user's favorite places, POIs, and addresses.
To obtain an instance of the favorites data provider and invoke the ServiceProvider.INSTANCE.favoritesDataProvider()
method:
val favoritesDataProvider = ServiceProvider.INSTANCE.favoritesDataProvider()
The priority of the favorite data provider is equal to FavoritesDataProvider.priotiry
.
The favorite data provider stores data in FavoriteRecord
. One unique feature of this record is that the user doesn't have to specify IndexableRecord.indexTokens
. Index tokens will be constructed from IndexableRecord.address
data.
Use the FavoritesDataProvider.getAll()
method to get all favorite records:
val task = favoritesDataProvider.getAll(object : CompletionCallback<List<FavoriteRecord>> {
override fun onComplete(result: List<FavoriteRecord>) {
}
override fun onError(e: Exception) {
}
})
Save a new favorite record, access all saved favorites, and receive notifications about changes to saved favorites.
History Data Provider
The main purpose of HistoryDataProvider
is to keep information about recently accessed SearchResults
. The Search SDK UI module uses data from the history data provider to prepare and show the "Recent searches" section in SearchResultsView
.
To obtain an instance of the history data provider and invoke the ServiceProvider.INSTANCE.historyDataProvider()
method:
val historyDataProvider = ServiceProvider.INSTANCE.historyDataProvider()
The priority of the history data provider is equal to HistoryDataProvider.priority
.
The history data provider stores data in HistoryRecord
. Similar to FavoriteRecord
, this record constructs IndexableRecord.indexTokens
from IndexableRecord.address
data. Also, HistoryRecord
introduces new property: timestamp
. HistoryDataProvider
and the Search SDK UI module use this property to sort history records by relevance.
Use the HistoryDataProvider.getAll()
method to get all history records:
val task = historyDataProvider.getAll(object : CompletionCallback<List<HistoryRecord>> {
override fun onComplete(result: List<HistoryRecord>) {
}
override fun onError(e: Exception) {
}
})
Access saved search history records.
Custom data providers
The Mapbox Search SDK for Android allows you create your own data providers if you want to introduce custom POIs or addresses to the search engine during the search.
Search across POIs provided by custom data provider
First, you should create a record class that will store all the data about places, POIs, and addresses that you have. Implement an IndexableRecord
interface. We recommend using a Kotlin data class
and @Parcelize
annotation from the kotlin-parcelize
plugin to ease implementation:
@Parcelize
data class CustomRecord(
override val id: String,
override val name: String,
override val coordinate: Point,
override val type: SearchResultType,
override val descriptionText: String?,
override val address: SearchAddress?,
override val routablePoints: List<RoutablePoint>?,
override val categories: List<String>?,
override val makiIcon: String?,
override val metadata: SearchResultMetadata?,
override val indexTokens: List<String>,
) : IndexableRecord
Then, implement an IndexableDataProvider
interface that will be used as a source of custom records and will update the search engine index associated with the provided IndexableDataProviderEngine
instance.
Search engines will only be able to search across custom data if you've added custom data to IndexableDataProviderEngine
. Make sure you've provided your data to the data provider engine once data is available. Read more about data provider engines in data provider engine section.
And finally, register custom data provider in your SearchEngine
:
val searchEngine: SearchEngine = //...
val customDataProvider: CustomDataProvider = // ...
val task = searchEngine.registerDataProvider(
customDataProvider,
callback = object : CompletionCallback<Unit> {
override fun onComplete(result: Unit) {
}
override fun onError(e: Exception) {
}
}
)
If you want to remove your custom data from search engine indexes, unregister your custom data provider from the SearchEngine
:
val task = searchEngine.unregisterDataProvider(
customDataProvider,
callback = object : CompletionCallback<Unit> {
override fun onComplete(result: Unit) {
}
override fun onError(e: Exception) {
}
}
)