diff --git a/lib/shared/search-index.js b/lib/shared/search-index.js
--- a/lib/shared/search-index.js
+++ b/lib/shared/search-index.js
@@ -2,6 +2,8 @@
 
 import Tokenizer from 'tokenize-text';
 
+import RadixTree from './radix-tree.js';
+
 type Token = {
   index: number,
   match: {
@@ -20,30 +22,14 @@
 
 class SearchIndex {
   tokenize: (str: string) => Token[];
-  fullTextIndex: { [token: string]: Set<string> };
-  partialTextIndex: { [token: string]: Set<string> };
+  radixTree: RadixTree<string> = new RadixTree<string>();
 
   constructor(inputTokenize?: TokenizeFunc) {
     this.tokenize = inputTokenize ?? defaultTokenize;
-    this.fullTextIndex = {};
-    this.partialTextIndex = {};
   }
 
   addAllPrefixes(id: string, value: string): void {
-    if (this.fullTextIndex[value] === undefined) {
-      this.fullTextIndex[value] = new Set();
-    }
-    this.fullTextIndex[value].add(id);
-    let partialString = '';
-    for (let i = 0; i < value.length; i++) {
-      const char = value[i];
-      partialString += char;
-      // TODO probably should do some stopwords here
-      if (this.partialTextIndex[partialString] === undefined) {
-        this.partialTextIndex[partialString] = new Set();
-      }
-      this.partialTextIndex[partialString].add(id);
-    }
+    this.radixTree.add(value, id);
   }
 
   addEntry(id: string, rawText: string) {
@@ -63,20 +49,21 @@
     const lastKeyword = keywords[keywords.length - 1];
     const lastKeywordValue = lastKeyword.value.toLowerCase();
     const lastMatchSet = lastKeyword.match.input.match(/\S$/)
-      ? this.partialTextIndex[lastKeywordValue]
-      : this.fullTextIndex[lastKeywordValue];
-    if (!lastMatchSet) {
+      ? this.radixTree.getAllMatchingPrefix(lastKeywordValue)
+      : this.radixTree.getAllMatchingExactly(lastKeywordValue);
+    if (lastMatchSet.length === 0) {
       return [];
     }
     const fullKeywords = keywords.slice(0, -1).map(k => k.value.toLowerCase());
 
-    let possibleMatches: string[] = Array.from(lastMatchSet);
+    let possibleMatches = lastMatchSet;
     for (const keyword of fullKeywords) {
-      const fullMatches = this.fullTextIndex[keyword];
-      if (!fullMatches) {
+      const fullMatches = this.radixTree.getAllMatchingExactly(keyword);
+      if (fullMatches.length === 0) {
         return [];
       }
-      possibleMatches = possibleMatches.filter(id => fullMatches.has(id));
+      const fullMatchesSet = new Set(fullMatches);
+      possibleMatches = possibleMatches.filter(id => fullMatchesSet.has(id));
       if (possibleMatches.length === 0) {
         return [];
       }
diff --git a/lib/shared/sentence-prefix-search-index.js b/lib/shared/sentence-prefix-search-index.js
--- a/lib/shared/sentence-prefix-search-index.js
+++ b/lib/shared/sentence-prefix-search-index.js
@@ -26,11 +26,7 @@
   }
 
   getSearchResults(query: string): string[] {
-    const transformedQuery = query.toLowerCase();
-    if (this.partialTextIndex[transformedQuery]) {
-      return Array.from(this.partialTextIndex[transformedQuery]);
-    }
-    return [];
+    return this.radixTree.getAllMatchingPrefix(query.toLowerCase());
   }
 }