diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3941,6 +3941,7 @@
     'PhabricatorSearchEngineAttachment' => 'applications/search/engineextension/PhabricatorSearchEngineAttachment.php',
     'PhabricatorSearchEngineExtension' => 'applications/search/engineextension/PhabricatorSearchEngineExtension.php',
     'PhabricatorSearchEngineExtensionModule' => 'applications/search/engineextension/PhabricatorSearchEngineExtensionModule.php',
+    'PhabricatorSearchFerretNgramGarbageCollector' => 'applications/search/garbagecollector/PhabricatorSearchFerretNgramGarbageCollector.php',
     'PhabricatorSearchField' => 'applications/search/field/PhabricatorSearchField.php',
     'PhabricatorSearchHost' => 'infrastructure/cluster/search/PhabricatorSearchHost.php',
     'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php',
@@ -9522,6 +9523,7 @@
     'PhabricatorSearchEngineAttachment' => 'Phobject',
     'PhabricatorSearchEngineExtension' => 'Phobject',
     'PhabricatorSearchEngineExtensionModule' => 'PhabricatorConfigModule',
+    'PhabricatorSearchFerretNgramGarbageCollector' => 'PhabricatorGarbageCollector',
     'PhabricatorSearchField' => 'Phobject',
     'PhabricatorSearchHost' => 'Phobject',
     'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController',
diff --git a/src/applications/search/garbagecollector/PhabricatorSearchFerretNgramGarbageCollector.php b/src/applications/search/garbagecollector/PhabricatorSearchFerretNgramGarbageCollector.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/garbagecollector/PhabricatorSearchFerretNgramGarbageCollector.php
@@ -0,0 +1,55 @@
+<?php
+
+final class PhabricatorSearchFerretNgramGarbageCollector
+  extends PhabricatorGarbageCollector {
+
+  const COLLECTORCONST = 'search.ferret.ngram';
+
+  public function getCollectorName() {
+    return pht('Ferret Engine Ngrams');
+  }
+
+  public function hasAutomaticPolicy() {
+    return true;
+  }
+
+  protected function collectGarbage() {
+    $all_objects = id(new PhutilClassMapQuery())
+      ->setAncestorClass('PhabricatorFerretInterface')
+      ->execute();
+
+    $did_collect = false;
+    foreach ($all_objects as $object) {
+      $engine = $object->newFerretEngine();
+      $conn = $object->establishConnection('w');
+
+      $ngram_row = queryfx_one(
+        $conn,
+        'SELECT ngram FROM %T WHERE needsCollection = 1 LIMIT 1',
+        $engine->getCommonNgramsTableName());
+      if (!$ngram_row) {
+        continue;
+      }
+
+      $ngram = $ngram_row['ngram'];
+
+      queryfx(
+        $conn,
+        'DELETE FROM %T WHERE ngram = %s',
+        $engine->getNgramsTableName(),
+        $ngram);
+
+      queryfx(
+        $conn,
+        'UPDATE %T SET needsCollection = 0 WHERE ngram = %s',
+        $engine->getCommonNgramsTableName(),
+        $ngram);
+
+      $did_collect = true;
+      break;
+    }
+
+    return $did_collect;
+  }
+
+}
diff --git a/src/applications/search/management/PhabricatorSearchManagementNgramsWorkflow.php b/src/applications/search/management/PhabricatorSearchManagementNgramsWorkflow.php
--- a/src/applications/search/management/PhabricatorSearchManagementNgramsWorkflow.php
+++ b/src/applications/search/management/PhabricatorSearchManagementNgramsWorkflow.php
@@ -6,7 +6,10 @@
   protected function didConstruct() {
     $this
       ->setName('ngrams')
-      ->setSynopsis(pht('Recompute common ngrams.'))
+      ->setSynopsis(
+        pht(
+          'Recompute common ngrams. This is an advanced workflow that '.
+          'can harm search quality if used improperly.'))
       ->setArguments(
         array(
           array(