silverstripe-fulltextsearch/docs/en/04_querying.md

4.6 KiB

Querying

This is where the magic happens. You will construct the search terms and other parameters required to form a SearchQuery object, and pass that into a SearchIndex to get results.

Building a SearchQuery

First, you'll need to construct a new SearchQuery object:

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;

$query = SearchQuery::create();

You can then alter the SearchQuery with a number of methods:

addSearchTerm()

The simplest - pass through a string to search your index for.

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;

$query = SearchQuery::create()
    ->addSearchTerm('fire');

You can also limit this to specific fields by passing an array as the second argument, specified in the form of {table}_{field}:

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use Page;

$query = SearchQuery::create()
    ->addSearchTerm('on fire', [Page::class . '_Title']);

addFuzzySearchTerm()

Pass through a string to search your index for, with "fuzzier" matching - this means that a term like "fishing" would also likely find results containing "fish" or "fisher". Otherwise behaves the same as addSearchTerm().

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;

$query = SearchQuery::create()
    ->addFuzzySearchTerm('fire');

addClassFilter()

Only query a specific class in the index, optionally including subclasses.

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use My\Namespace\PageType\SpecialPage;

$query = SearchQuery::create()
    ->addClassFilter(SpecialPage::class, false); // only return results from SpecialPages, not subclasses

Searching value ranges

Most values can be expressed as ranges, most commonly dates or numbers. To search for a range of values rather than an exact match, use the SearchQuery_Range class. The range can include bounds on both sides, or stay open-ended by simply leaving the argument blank. It takes arguments in the form of SearchQuery_Range::create($start, $end)):

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery_Range;
use My\Namespace\Index\MyIndex;
use Page;

$query = SearchQuery::create()
    ->addSearchTerm('fire')
    // Only include documents edited in 2011 or earlier
    ->addFilter(Page::class . '_LastEdited', SearchQuery_Range::create(null, '2011-12-31T23:59:59Z'));
$results = MyIndex::singleton()->search($query);

How do I use date ranges where dates might not be defined?

The Solr index updater only includes dates with values, so the field might not exist in all your index entries. A simple bounded range query (<field>:[* TO <date>]) will fail in this case. In order to query the field, reverse the search conditions and exclude the ranges you don't want:

// Wrong: Filter will ignore all empty field values
$query->addFilter('fieldname', SearchQuery_Range::create('*', 'somedate'));

// Right: Exclude the opposite range
$query->addExclude('fieldname', SearchQuery_Range::create('somedate', '*'));

Note: At the moment, the date format is specific to the search implementation.

Empty or existing values

Since there's a type conversion between the SilverStripe database, object properties and the search index persistence, it's often not clear which condition is searched for. Should it equal an empty string, or only match if the field wasn't indexed at all? The SearchQuery API has the concept of a "missing" and "present" field value for this:

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use My\Namespace\Index\MyIndex;
use Page;

$query = SearchQuery::create()
    ->addSearchTerm('fire');
    // Needs a value, although it can be false
    ->addFilter(Page::class . '_ShowInMenus', SearchQuery::$present);
$results = MyIndex::singleton()->search($query);

Executing your query

Once you have your query constructed, you need to run it against your index.

use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use My\Namespace\Index\MyIndex;

$query = SearchQuery::create()->addSearchTerm('fire');
$results = MyIndex::singleton()->search($query);

The return value of a search() call is an object which contains a few properties:

  • Matches: ArrayList of the current "page" of search results.
  • Suggestion: (optional) Any suggested spelling corrections in the original query notation
  • SuggestionNice: (optional) Any suggested spelling corrections for display (without query notation)
  • SuggestionQueryString (optional) Link to repeat the search with suggested spelling corrections