From 1b0912bbea512f04a5cb1dd4afabdd064efa6de2 Mon Sep 17 00:00:00 2001 From: Chris Penny Date: Wed, 6 Nov 2024 13:49:18 +1300 Subject: [PATCH] Use new spelling suggestions feature. Update controller configuration (#12) --- README.md | 47 +++++++++++++++++++ composer.json | 2 +- src/Controller/SearchResultsController.php | 37 ++++++++++----- .../Discoverer/Service/Results/Suggestions.ss | 2 +- .../Page/Layout/SearchResults.ss | 4 +- 5 files changed, 77 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0b7afa2..90da897 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,53 @@ This search UI assumes that you have the following fields available in your inde * `content` (optional) * `body` (optional) +## Spelling suggestions (aka "did you mean") + +**Not to be confused with Query suggestions (aka autocomplete).** + +Spelling suggestions for queries can be enabled with the following environment variable. + +```yaml +SEARCH_SPELLING_SUGGESTIONS_ENABLED=1 +``` + +Note: Spelling suggestions is an API query that happens **after** you have received results - so it will impact your +page load times. + +The spelling suggestions feature needs to know what fields you would like it to search in. By default, it **only** +provides suggestions based on the `title` field. You can add additional fields by updating the following configuration. + +```yaml +SilverStripe\DiscovererSearchUI\Controller\SearchResultsController: + spelling_suggestion_fields: + - content + - body +``` + +By default, these suggestions will be provided when you have zero (`0`) search results. This default can be updated +through the following configruation. + +```yaml +SilverStripe\DiscovererSearchUI\Controller\SearchResultsController: + result_count_for_spelling_suggestions: 5 +``` + +By default, you will receive (up to) 1 suggestion (there aren't always spelling suggestions for a given query). This +default can be udpated through the following configuration. + +```yaml +SilverStripe\DiscovererSearchUI\Controller\SearchResultsController: + spelling_suggestions_limit: 5 +``` + +Some services support both "raw" and "foramtted" results for spelling suggestions. Our default behaviour is to **not** +request formatted suggestions. You can enable this in your requests through the following configuration. + +```yaml +SilverStripe\DiscovererSearchUI\Controller\SearchResultsController: + spelling_suggestions_formatted: true +``` + ## Customisations The out of the box `SearchResultsController` comes with 3 extension points that will allow you to modify the search diff --git a/composer.json b/composer.json index 638cce4..bf64e62 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ ], "require": { "silverstripe/framework": "^5", - "silverstripe/silverstripe-discoverer": "^1.2" + "silverstripe/silverstripe-discoverer": "^2" }, "config": { "allow-plugins": { diff --git a/src/Controller/SearchResultsController.php b/src/Controller/SearchResultsController.php index 0d39dc6..a379b13 100644 --- a/src/Controller/SearchResultsController.php +++ b/src/Controller/SearchResultsController.php @@ -19,7 +19,7 @@ class SearchResultsController extends PageController { - public const ENV_SUGGESTIONS_ENABLED = 'SEARCH_SUGGESTIONS_ENABLED'; + private const ENV_SPELLING_SUGGESTIONS_ENABLED = 'SEARCH_SPELLING_SUGGESTIONS_ENABLED'; private static array $allowed_actions = [ 'SearchForm', @@ -35,9 +35,15 @@ class SearchResultsController extends PageController private static int $per_page = 10; - private static int $result_count_for_suggestions = 0; + private static int $result_count_for_spelling_suggestions = 0; - private static int $suggestions_limit = 4; + private static int $spelling_suggestions_limit = 1; + + private static bool $spelling_suggestions_formatted = false; + + private static array $spelling_suggestion_fields = [ + 'title', + ]; private ?Results $results = null; @@ -84,7 +90,7 @@ public function SearchForm(): Form public function SearchResults(): ?Results { - // Local cache to make sure we don't perform this task more than one (@see QuerySuggestions()) + // Local cache to make sure we don't perform this task more than one (@see SpellingSuggestions()) if ($this->results) { return $this->results; } @@ -123,21 +129,22 @@ public function SearchResults(): ?Results return $this->results; } - public function QuerySuggestions(): ?Suggestions + public function SpellingSuggestions(): ?Suggestions { - if (!Environment::getEnv(self::ENV_SUGGESTIONS_ENABLED)) { + if (!Environment::getEnv(self::ENV_SPELLING_SUGGESTIONS_ENABLED)) { return null; } // Get the search results for this request $results = $this->SearchResults(); + // No search has been performed yet if (!$results) { return null; } // Our results contain enough records that we don't want to query for suggestions - if ($results->getRecords()->count() > $this->config()->get('result_count_for_suggestions')) { + if ($results->getRecords()->count() > $this->config()->get('result_count_for_spelling_suggestions')) { return null; } @@ -146,24 +153,32 @@ public function QuerySuggestions(): ?Suggestions $fieldKeywords = $this->config()->get('field_keywords'); // The keywords that are being searched $keywords = $request->getVar($fieldKeywords); + // The fields that we want to query on + $suggestionFields = $this->config()->get('spelling_suggestion_fields'); + // Whether we want to have formatted results (if supported by our search service) + $suggestionsFormatted = $this->config()->get('spelling_suggestions_formatted'); // The index variant that we are fetching records from (as defined under `indexes` in search.yml) $index = $this->config()->get('index_variant'); $service = SearchService::singleton(); - $suggestion = Suggestion::create($keywords); - $suggestion->setLimit($this->config()->get('suggestions_limit')); + $suggestion = Suggestion::create( + $keywords, + $this->config()->get('spelling_suggestions_limit'), + $suggestionFields, + $suggestionsFormatted + ); $this->invokeWithExtensions('updateSuggestionQuery', $suggestion); - $suggestions = $service->querySuggestion($suggestion, $index); + $suggestions = $service->spellingSuggestion($suggestion, $index); if (!$suggestions->getSuggestions()) { return null; } $suggestions->setTargetQueryUrl($this->dataRecord->Link()); - $suggestions->setTargetQueryStringField($this->config()->get('field_keywords')); + $suggestions->setTargetQueryStringField($fieldKeywords); return $suggestions; } diff --git a/templates/SilverStripe/Discoverer/Service/Results/Suggestions.ss b/templates/SilverStripe/Discoverer/Service/Results/Suggestions.ss index 0bb387c..639e49b 100644 --- a/templates/SilverStripe/Discoverer/Service/Results/Suggestions.ss +++ b/templates/SilverStripe/Discoverer/Service/Results/Suggestions.ss @@ -2,7 +2,7 @@ <% loop $Me %> <% if $Up.TargetQueryUrl && $Up.TargetQueryStringField %>
  • - $Me
  • diff --git a/templates/SilverStripe/DiscovererSearchUI/Page/Layout/SearchResults.ss b/templates/SilverStripe/DiscovererSearchUI/Page/Layout/SearchResults.ss index 51d257e..2b1d485 100644 --- a/templates/SilverStripe/DiscovererSearchUI/Page/Layout/SearchResults.ss +++ b/templates/SilverStripe/DiscovererSearchUI/Page/Layout/SearchResults.ss @@ -3,11 +3,11 @@ $SearchForm - <% if $QuerySuggestions %> + <% if $SpellingSuggestions %>

    <%t SilverStripe\DiscovererSearchUI\Page\SearchResults.SearchSuggestions 'Search suggestions' %>

    - $QuerySuggestions + $SpellingSuggestions
    <% end_if %>