Skip to content

Commit 94e88bc

Browse files
authored
Different tag index: document index lists for each tag. (#8396)
1 parent 0ae8640 commit 94e88bc

File tree

3 files changed

+43
-43
lines changed

3 files changed

+43
-43
lines changed

app/lib/search/mem_index.dart

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ class InMemoryPackageIndex {
2828
late final TokenIndex<String> _readmeIndex;
2929
late final TokenIndex<IndexedApiDocPage> _apiSymbolIndex;
3030
late final _scorePool = ScorePool(_packageNameIndex._packageNames);
31-
final _tagIds = <String, int>{};
31+
32+
/// Maps the tag strings to a list of document index values
33+
/// (`PackageDocument doc.tags -> List<_documents.indexOf(doc)>`).
34+
final _tagDocumentIndices = <String, List<int>>{};
3235
final _documentTagIds = <List<int>>[];
3336

3437
/// Adjusted score takes the overall score and transforms
@@ -63,7 +66,7 @@ class InMemoryPackageIndex {
6366
// transform tags into numberical IDs
6467
final tagIds = <int>[];
6568
for (final tag in doc.tags) {
66-
tagIds.add(_tagIds.putIfAbsent(tag, () => _tagIds.length));
69+
_tagDocumentIndices.putIfAbsent(tag, () => []).add(i);
6770
}
6871
tagIds.sort();
6972
_documentTagIds.add(tagIds);
@@ -134,11 +137,7 @@ class InMemoryPackageIndex {
134137
PackageSearchResult search(ServiceSearchQuery query) {
135138
// prevent any work if offset is outside of the range
136139
if ((query.offset ?? 0) > _documents.length) {
137-
return PackageSearchResult(
138-
timestamp: clock.now(),
139-
totalCount: 0,
140-
packageHits: [],
141-
);
140+
return PackageSearchResult.empty();
142141
}
143142
return _scorePool.withScore(
144143
value: 1.0,
@@ -162,49 +161,36 @@ class InMemoryPackageIndex {
162161
final combinedTagsPredicate =
163162
query.tagsPredicate.appendPredicate(query.parsedQuery.tagsPredicate);
164163
if (combinedTagsPredicate.isNotEmpty) {
165-
// The list of predicate tag entries, converted to tag IDs (or -1 if there is no indexed tag),
166-
// sorted by their id.
167-
final entriesToCheck = combinedTagsPredicate.entries
168-
.map((e) => MapEntry(_tagIds[e.key] ?? -1, e.value))
169-
.toList()
170-
..sort((a, b) => a.key.compareTo(b.key));
171-
172-
packageScores.retainWhere((docIndex, _) {
173-
// keeping track of tag id iteration with the `nextTagIndex`
174-
final tagIds = _documentTagIds[docIndex];
175-
var nextTagIndex = 0;
176-
177-
for (final entry in entriesToCheck) {
178-
if (entry.key == -1) {
179-
// no tag id is present for this predicate
180-
if (entry.value) {
181-
// the predicate is required, no document will match it
182-
return false;
183-
} else {
184-
// the predicate is prohibited, no document has it, always a match
164+
for (final entry in combinedTagsPredicate.entries) {
165+
final docIndexes = _tagDocumentIndices[entry.key];
166+
167+
if (entry.value) {
168+
// predicate is required, zeroing the gaps between index values
169+
if (docIndexes == null) {
170+
// the predicate is required, no document will match it
171+
return PackageSearchResult.empty();
172+
}
173+
174+
for (var i = 0; i < docIndexes.length; i++) {
175+
if (i == 0) {
176+
packageScores.fillRange(0, docIndexes[i], 0.0);
185177
continue;
186178
}
179+
packageScores.fillRange(docIndexes[i - 1] + 1, docIndexes[i], 0.0);
187180
}
181+
packageScores.fillRange(docIndexes.last + 1, _documents.length, 0.0);
182+
} else {
183+
// predicate is prohibited, zeroing the values
188184

189-
// skipping the present tag ids until the currently matched predicate tag id
190-
while (nextTagIndex < tagIds.length &&
191-
tagIds[nextTagIndex] < entry.key) {
192-
nextTagIndex++;
185+
if (docIndexes == null) {
186+
// the predicate is prohibited, no document has it, always a match
187+
continue;
193188
}
194-
195-
// checking presence
196-
late bool present;
197-
if (nextTagIndex == tagIds.length) {
198-
present = false;
199-
} else {
200-
present = tagIds[nextTagIndex] == entry.key;
189+
for (final i in docIndexes) {
190+
packageScores.setValue(i, 0.0);
201191
}
202-
203-
if (entry.value && !present) return false;
204-
if (!entry.value && present) return false;
205192
}
206-
return true;
207-
});
193+
}
208194
}
209195

210196
// filter on dependency

app/lib/search/search_service.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,12 @@ class PackageSearchResult {
340340
}) : packageHits = packageHits ?? <PackageHit>[],
341341
sdkLibraryHits = sdkLibraryHits ?? <SdkLibraryHit>[];
342342

343+
factory PackageSearchResult.empty() => PackageSearchResult(
344+
timestamp: clock.now(),
345+
totalCount: 0,
346+
packageHits: [],
347+
);
348+
343349
PackageSearchResult.error({
344350
required this.errorMessage,
345351
required this.statusCode,

app/lib/search/token_index.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ class IndexedScore<K> {
219219
_values[index] = math.max(_values[index], value);
220220
}
221221

222+
/// Sets the positions greater than or equal to [start] and less than [end],
223+
/// to [fillValue].
224+
void fillRange(int start, int end, double fillValue) {
225+
assert(start <= end);
226+
if (start == end) return;
227+
_values.fillRange(start, end, fillValue);
228+
}
229+
222230
void removeWhere(bool Function(int index, K key) fn) {
223231
for (var i = 0; i < length; i++) {
224232
if (isNotPositive(i)) continue;

0 commit comments

Comments
 (0)