in app/lib/search/mem_index.dart [316:433]
_TextResults? _searchText(
Set<String> packages,
String? text, {
required bool hasHighlightedHit,
}) {
final sw = Stopwatch()..start();
if (text != null && text.isNotEmpty) {
final words = splitForQuery(text);
if (words.isEmpty) {
return _TextResults(Score.empty(), <String, List<String>>{});
}
bool aborted = false;
bool checkAborted() {
if (!aborted && sw.elapsed > _textSearchTimeout) {
aborted = true;
_logger.info(
'[pub-aborted-search-query] Aborted text search after ${sw.elapsedMilliseconds} ms.');
}
return aborted;
}
final nameScore =
_packageNameIndex.searchWords(words, packages: packages);
final descr =
_descrIndex.searchWords(words, weight: 0.90, limitToIds: packages);
final readme =
_readmeIndex.searchWords(words, weight: 0.75, limitToIds: packages);
final core = Score.max([nameScore, descr, readme]);
var symbolPages = Score.empty();
if (!checkAborted()) {
symbolPages = _apiSymbolIndex.searchWords(words, weight: 0.70);
}
// Do documentation text search only when there was no reasonable core result
// and no reasonable API symbol result.
var dartdocPages = Score.empty();
final shouldSearchApiText = !hasHighlightedHit &&
core.maxValue < 0.4 &&
symbolPages.maxValue < 0.3;
if (!checkAborted() && shouldSearchApiText) {
final sw = Stopwatch()..start();
dartdocPages = _apiDartdocIndex.searchWords(words, weight: 0.40);
_logger.info('[pub-search-query-with-api-dartdoc-index] '
'core: ${core.length}/${core.maxValue} '
'symbols: ${symbolPages.length}/${symbolPages.maxValue} '
'documentation: ${dartdocPages.length}/${dartdocPages.maxValue} '
'elapsed: ${sw.elapsed}');
} else {
_logger.info('[pub-search-query-without-api-dartdoc-index] '
'hasHighlightedHit: $hasHighlightedHit '
'core: ${core.length}/${core.maxValue} '
'symbols: ${symbolPages.length}/${symbolPages.maxValue}');
}
final logTags = [
if (symbolPages.isNotEmpty) '[pub-search-query-api-symbols-found]',
if (dartdocPages.isNotEmpty) '[pub-search-query-api-dartdoc-found]',
if (!hasHighlightedHit && symbolPages.maxValue > core.maxValue)
'[pub-search-query-api-symbols-better-than-core]',
if (!hasHighlightedHit && dartdocPages.maxValue > core.maxValue)
'[pub-search-query-api-dartdoc-better-than-core]',
if (!hasHighlightedHit && symbolPages.maxValue > dartdocPages.maxValue)
'[pub-search-query-api-dartdoc-better-than-symbols]',
];
if (logTags.isNotEmpty) {
_logger.info('[pub-search-query-api-improved] ${logTags.join(' ')}');
}
final apiDocScore = Score.max([symbolPages, dartdocPages]);
final apiPackages = <String, double>{};
for (String key in apiDocScore.getKeys()) {
final pkg = _apiDocPkg(key);
if (!packages.contains(pkg)) continue;
final value = apiDocScore[key];
apiPackages[pkg] = math.max(value, apiPackages[pkg] ?? 0.0);
}
final apiPkgScore = Score(apiPackages);
var score = Score.max([core, apiPkgScore])
.project(packages)
.removeLowValues(fraction: 0.2, minValue: 0.01);
// filter results based on exact phrases
final phrases = extractExactPhrases(text);
if (!aborted && phrases.isNotEmpty) {
final Map<String, double> matched = <String, double>{};
for (String package in score.getKeys()) {
final doc = _packages[package]!;
final bool matchedAllPhrases = phrases.every((phrase) =>
doc.package.contains(phrase) ||
doc.description!.contains(phrase) ||
doc.readme!.contains(phrase));
if (matchedAllPhrases) {
matched[package] = score[package];
}
}
score = Score(matched);
}
final apiDocKeys = apiDocScore.getKeys().toList()
..sort((a, b) => -apiDocScore[a].compareTo(apiDocScore[b]));
final topApiPages = <String, List<String>>{};
for (String key in apiDocKeys) {
final pkg = _apiDocPkg(key);
final pages = topApiPages.putIfAbsent(pkg, () => []);
if (pages.length < 3) {
final page = _apiDocPath(key);
pages.add(page);
}
}
return _TextResults(score, topApiPages);
}
return null;
}