File: suggest.md

package info (click to toggle)
firefox 147.0.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,683,320 kB
  • sloc: cpp: 7,607,359; javascript: 6,533,295; ansic: 3,775,223; python: 1,415,500; xml: 634,561; asm: 438,949; java: 186,241; sh: 62,752; makefile: 18,079; objc: 13,092; perl: 12,808; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10; exp: 6
file content (221 lines) | stat: -rw-r--r-- 7,007 bytes parent folder | download | duplicates (12)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# Suggest

The API for the `SuggestStore` can be found in the [MozillaComponents Kotlin documentation](https://mozilla.github.io/application-services/kotlin/kotlin-components-docs/mozilla.appservices.suggest/-suggest-store/index.html).

## Prerequisites

That {doc}`viaduct` must be initialized during application startup.

## Async

The Suggest API is synchronous, which means calling it directly will block the current
thread.  To deal with this, all current consumers wrap the API in order to make it async.  For
details on this wrapping, see the consumer code itself.

On JS, this wrapping is handled automatically by UniFFI.  See
https://searchfox.org/mozilla-central/source/toolkit/components/uniffi-bindgen-gecko-js/config.toml
for details on which functions/methods are wrapped to be async.

## Setting up the store

You need to import one or more of the following primitives to work with the `SuggestStore` (these come from the generated `suggest.kt` file, produced by `uniffi`):

:::{tab-set-code}

```kotlin
import mozilla.appservices.remotesettings.RemoteSettingsServer
import mozilla.appservices.suggest.SuggestApiException
import mozilla.appservices.suggest.SuggestIngestionConstraints
import mozilla.appservices.suggest.SuggestStore
import mozilla.appservices.suggest.SuggestStoreBuilder
import mozilla.appservices.suggest.Suggestion
import mozilla.appservices.suggest.SuggestionQuery
```

```swift
import MozillaAppServices
```

```js
ChromeUtils.defineESModuleGetters(lazy, {
  RemoteSettingsServer: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
  SuggestApiException: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
  SuggestIngestionConstraints: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
  SuggestStore: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
  SuggestStoreBuilder: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
  Suggestion: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
  SuggestionProvider: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
  SuggestionQuery: "moz-src:///toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs",
});
```

:::

Create a `SuggestStore` as a singleton. You do this via the `SuggestStoreBuilder`, which returns a `SuggestStore`. No I/O or network requests are performed during construction, which makes this safe to do at any point in the application startup:

:::{tab-set-code}
```kotlin
internal val store: SuggestStore = {
    SuggestStoreBuilder()
        .dataPath(context.getDatabasePath(DATABASE_NAME).absolutePath)
        .remoteSettingsServer(remoteSettingsServer)
        .build()
```

```swift
let store: SuggestStore = {
    let storeBuilder = SuggestStoreBuilder()
    storeBuilder.dataPath(context.getDatabasePath(DATABASE_NAME).absolutePath)
    storeBuilder.remoteSettingsServer(remoteSettingsServer)
    return storeBuilder.build()
}
```


```js
const store: SuggestStore = SuggestStoreBuilder()
    .dataPath(pathForSuggestDatabase)
    .remoteSettingsServer(remoteSettingsServer)
    .build();
}

:::

* You need to set the `dataPath`, which is the path (the SQLite location) where you store your suggestions.
* The `remoteSettingsServer` is only needed if you want to set the server to anything else but `prod`. If so, you pass a `RemoteSettingsServer` object.

## Ingesting suggestions

Ingesting suggestions happens in two different ways: On startup, and then, periodically, in the background.

* `SuggestIngestionConstraints` is used to control what gets ingested.
* Use the `providers` field to limit ingestion by provider type.
* Use the `providerConstraints` field to add additional constraints, currently this is only used for exposure suggestions.

### On Start Up

Ingest with `SuggestIngestionConstraints(emptyOnly=true)` shortly after each startup. This ensures we have something in the DB on the first run and also after upgrades where we often will clear the DB to start from scratch.

:::{tab-set-code}
```kotlin
store.ingest(SuggestIngestionConstraints(
    emptyOnly = true,
    providers = listOf(SuggestionProvider.AMP_MOBILE, SuggestionProvider.WIKIPEDIA, SuggestionProvider.WEATHER)
))
```

```swift
store.ingest(SuggestIngestionConstraints(
    emptyOnly: true,
    providers: [.AMP_MOBILE, .WIKIPEDIA, .WEATHER]
))
```

```js
store.ingest(SuggestIngestionConstraints(
    emptyOnly: true,
    providers: [SuggestionProvider.AMP_MOBILE, SuggestionProvider.WIKIPEDIA, SuggestionProvider.WEATHER]
))
```

:::

### Periodically

Ingest with `SuggestIngestionConstraints(emptyOnly=false)` on a regular schedule (like once a day).

:::{tab-set-code}
```kotlin
store.ingest(SuggestIngestionConstraints(
    emptyOnly = false,
    providers = listOf(SuggestionProvider.AMP_MOBILE, SuggestionProvider.WIKIPEDIA, SuggestionProvider.WEATHER)
))
```

```swift
store.ingest(SuggestIngestionConstraints(
    emptyOnly: false,
    providers: [.AMP_MOBILE, .WIKIPEDIA, .WEATHER]
))
```


```js
store.ingest(SuggestIngestionConstraints(
    emptyOnly: false,
    providers: [SuggestionProvider.AMP_MOBILE, SuggestionProvider.WIKIPEDIA, SuggestionProvider.WEATHER]
))
```
:::

## Querying Suggestions

Call `SuggestStore::query` to fetch suggestions for the suggest bar. The `providers` parameter should be the same value that got passed to `ingest()`.

:::{tab-set-code}
```kotlin
store.query(
    SuggestionQuery(
        keyword = text,
        providers = listOf(SuggestionProvider.AMP_MOBILE, SuggestionProvider.WIKIPEDIA, SuggestionProvider.WEATHER),
        limit = MAX_NUM_OF_FIREFOX_SUGGESTIONS,
    ),
)
```

```swift
store.query(
    SuggestionQuery(
        keyword: text,
        providers: [.AMP_MOBILE, .WIKIPEDIA, .WEATHER],
        limit: MAX_NUM_OF_FIREFOX_SUGGESTIONS
    )
)
```

```js
store.query(
    SuggestionQuery(
        keyword = text,
        providers = [SuggestionProvider.AMP_MOBILE, SuggestionProvider.WIKIPEDIA, SuggestionProvider.WEATHER],
        limit = MAX_NUM_OF_FIREFOX_SUGGESTIONS,
    ),
)
```
:::

## Interrupt querying

Call `interrupt()` with `InterruptKind::Read` to interrupt any in-progress queries when the user cancels a query and before running the next query.

:::{tab-set-code}
```kotlin
store.interrupt(InterruptKind.READ)
```

```swift
store.interrupt(kind: InterruptKind.READ)
```

```js
store.interrupt(InterruptKind.READ)
```
:::

## Shutdown the store

On shutdown, call `interrupt()` with `InterruptKind::ReadWrite` to interrupt any in-progress ingestion in addition to queries.

:::{tab-set-code}
```kotlin
store.interrupt(InterruptKind.READ_WRITE)
```

```swift
store.interrupt(kind: InterruptKind.READ_WRITE)
```

```js
store.interrupt(InterruptKind.READ_WRITE)
```
:::