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:
```php
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.
```php
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}`:
```php
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
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()`.
```php
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
$query = SearchQuery::create()
->addFuzzySearchTerm('fire');
```
### `addClassFilter()`
Only query a specific class in the index, optionally including subclasses.
```php
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))`:
```php
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
### 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:
```php
// Wrong: Filter will ignore all empty field values
`SearchCriteria` has a property called `$clauses` which is a collection of `SearchCriterion` (above) and/or `SearchCriteria` (allowing for infinite nesting of clauses), along with the conjunction used between each clause (IE: `AND`, `OR`). We want to build up our `SearchCriteria` by adding to it's `$clauses` collection.
`SearchCriteria` can either be passed an object that implements `SearchCriteriaInterface`, or it can be passed the `Target`, `Value`, and `Comparison` (like above).
#### Method 1
Instantiate a new `SearchCriteria` by providing an already instantiated `SearchCriterion` object. This `$criterion` will be added as the first item in the `$clauses` collection.
```php
$criteria = SearchCriteria::create($criterion);
```
#### Method 2
Instantiate a new `SearchCriteria` objects and define the `Target`, `Value`, and `Comparison`. `SearchCriteria` will create a new `SearchCriterion` object based on the values, and add it to the `$clauses` collection.
Our `SearchQuery` class now has a property called `$criteria` which holds all of our `SearchCriteria`. You can add new `SearchCriteria` by using `SearchQuery::filterBy()`.
#### Method 1
Pass in an already instantiated `SearchCriteria` object. If you implemented complex filtering (above), you will probably need to follow this method - fully creating your `SearchCriteria` first, and then passing it to the `SearchQuery`.
```php
$query->filterBy($criteria);
```
#### Method 2a
Where basic (single level) filtering is ok, the `SearchQuery::filterBy()` method can be used to create your `SearchCriterion` and `SearchCriteria` object.
Each item in the `$criteria` collection are treated with an `AND` conjunction (matching current `filter`/`exclude` functionality).
### Search Query Writers
Provided are 3 different `SearchQueryWriter`s for Solr:
*`SolrSearchQueryWriter_Basic`
*`SolrSearchQueryWriter_In`
*`SolrSearchQueryWriter_Range`
When these Writers are provided a `SearchCriterion`, they will generate the desired query string.
### Search Adapters
Search Adapters need to provide the following information:
* What is the search engine's conjunction strings? (EG: are they "AND" and "OR", or are they "&&" and "||", etc).
* What is the desired comparison container string? (EG: "**+(** query here **)**") for Solr).
* Most importantly - how to generate the query string from a `SearchCriterion`.
The `SolrSearchAdapter` uses `SearchQueryWriter`s (above) to generate query strings from a `SearchCriterion`.
### Customising your `SearchCriterion`/`SearchQueryWriter`
If you find that you do not want your `SearchCriterion` being parsed by one of the default `SearchQueryWriter`s (for whatever reason), you can optionally pass your own `SearchQueryWriter` to your `SearchCriterion` either as the **fourth parameter** when instantiating it, or by calling `setSearchQueryWriter()`.
If this value is set, then the (default Solr) Adapter will always use the provided `SearchQueryWriter`, rather than deciding for itself.
This should allow you to have full control over how your query strings are being generated if the default `SearchQueryWriter`s are not cutting it for you.