Full-Text Search


  • This article is about running a full-text search with a dynamic query.
    To learn how to run a full-text search using a static-index, see full-text search with index.

  • Use the search() method to query for documents that contain specified term/s within the text of the specified document field/s.

  • When running a full-text search with a dynamic query, the auto-index created by the server breaks down the text of the searched document field using the default search analyzer.
    All generated terms are lower-cased, so the search is case-insensitive.

  • Gain additional control over term tokenization by running a full-text search using a static-index, where the used analyzer is configurable.

  • A boost value can be set for each search to prioritize results. Learn more in boost search results.

  • User experience can be enhanced by requesting text fragments that highlight the searched terms in the results. Learn more in highlight search results.



Search for single term

/** @var array<Employee> $employees */
$employees = $session
    // Make a dynamic query on Employees collection
    ->query(Employee::class)
    // * Call 'Search' to make a Full-Text search
    // * Search is case-insensitive
    // * Look for documents containing the term 'University' within their 'Notes' field
    ->search("Notes", "University")
    ->toList();

// Results will contain Employee documents that have
// any case variation of the term 'university' in their 'Notes' field.
/** @var array<Employee> $employees */
$employees = $session->advanced()
    // Make a dynamic DocumentQuery on Employees collection
    ->documentQuery(Employee::class)
    // * Call 'Search' to make a Full-Text search
    // * Search is case-insensitive
    // * Look for documents containing the term 'University' within their 'Notes' field
    ->search("Notes", "University")
    ->toList();

// Results will contain Employee documents that have
// any case variation of the term 'university' in their 'Notes' field.
from "Employees"
where search(Notes, "University")

  • Executing the above query will generate the auto-index Auto/Employees/BySearch(Notes).

  • This auto-index will contain the following two index-fields:

    • Notes
      Contains terms with the original text from the indexed document field 'Notes'.
      Text is lower-cased and Not tokenized.

    • search(Notes)
      Contains lower-cased terms that were tokenized from the 'Notes' field by the default search analyzer (RavenStandardAnalyzer). Calling the search() method targets these terms to find matching documents.

Search for multiple terms

  • You can search for multiple terms in the same field in a single search method.

  • By default, the logical operator between these terms is 'OR'.

  • This behavior can be modified. See section Search operators.

Pass terms in a string:

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    // * Pass multiple terms in a single string, separated by spaces.
    // * Look for documents containing either 'University' OR 'Sales' OR 'Japanese'
    //   within their 'Notes' field
    ->search("Notes", "University Sales Japanese")
    ->toList();

// * Results will contain Employee documents that have at least one of the specified terms.
// * Search is case-insensitive.
/** @var array<Employee> $employees */
$employees = $session->advanced()
    ->documentQuery(Employee::class)
    // * Pass multiple terms in a single string, separated by spaces.
    // * Look for documents containing either 'University' OR 'Sales' OR 'Japanese'
    //   within their 'Notes' field
    ->search("Notes", "University Sales Japanese")
    ->toList();

// * Results will contain Employee documents that have at least one of the specified terms.
// * Search is case-insensitive.
from "Employees"
where search(Notes, "University Sales Japanese")

Pass terms in a list:

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    // * Pass terms in array<string>.
    // * Look for documents containing either 'University' OR 'Sales' OR 'Japanese'
    //   within their 'Notes' field
    ->search("Notes", ["University", "Sales", "Japanese"])
    ->toList();

// * Results will contain Employee documents that have at least one of the specified terms.
// * Search is case-insensitive.
from "Employees"
where search(Notes, "University Sales Japanese")

Search in multiple fields

  • You can search for terms in different fields by making multiple search calls.

  • By default, the logical operator between consecutive search methods is 'OR'.

  • This behavior can be modified. See section Search operators.

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    // * Look for documents containing:
    //   'French' in their 'Notes' field OR 'President' in their 'Title' field
    ->search("Notes", "French")
    ->search("Title", "President")
    ->toList();

// * Results will contain Employee documents that have
//   at least one of the specified fields with the specified terms.
// * Search is case-insensitive.
/** @var array<Employee> $employees */
$employees = $session->advanced()
    ->documentQuery(Employee::class)
    // * Look for documents containing:
    //   'French' in their 'Notes' field OR 'President' in their 'Title' field
    ->search("Notes", "French")
    ->search("Title", "President")
    ->toList();

// * Results will contain Employee documents that have
//   at least one of the specified fields with the specified terms.
// * Search is case-insensitive.
from "Employees"
where (search(Notes, "French") or search(Title, "President"))

Search in complex object

  • You can search for terms within a complex object.

  • Any nested text field within the object is searchable.

/** @var array<Company> $companies */
$companies = $session
    ->query(Company::class)
    // * Look for documents that contain:
    //   the term 'USA' OR 'London' in any field within the complex 'Address' object
    ->search("Address", "USA London")
    ->toList();

// * Results will contain Company documents that are located either in 'USA' OR in 'London'.
// * Search is case-insensitive.
/** @var array<Company> $companies */
$companies = $session->advanced()
    ->documentQuery(Company::class)
    // * Look for documents that contain:
    //   the term 'USA' OR 'London' in any field within the complex 'Address' object
    ->search("Address", "USA London")
    ->toList();

// * Results will contain Company documents that are located either in 'USA' OR in 'London'.
// * Search is case-insensitive.
from "Companies"
where search(Address, "USA London")

Search operators

  • By default, the logical operator between multiple terms within the same field in a search call is OR.

  • This can be modified using the @operator parameter as follows:

AND:

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    // * Pass operator with SearchOperator::and()
    ->search("Notes", "College German", SearchOperator::and())
    ->toList();

// * Results will contain Employee documents that have BOTH 'College' AND 'German'
//   in their 'Notes' field.
// * Search is case-insensitive.
/** @var array<Employee> $employees */
$employees = $session->advanced()
    ->documentQuery(Employee::class)
    // * Pass operator with SearchOperator::and()
    ->search("Notes", "College German", SearchOperator::and())
    ->toList();

// * Results will contain Employee documents that have BOTH 'College' AND 'German'
//   in their 'Notes' field.
// * Search is case-insensitive.
from "Employees"
where search(Notes, "College German", and)

OR:

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    // * Pass operator with SearchOperator::or()
    ->search("Notes", "College German", SearchOperator::or())
    ->toList();

// * Results will contain Employee documents that have EITHER 'College' OR 'German'
//   in their 'Notes' field.
// * Search is case-insensitive.
/** @var array<Employee> $employees */
$employees = $session->advanced()
    ->documentQuery(Employee::class)
    // * Pass operator with SearchOperator::or()
    ->search("Notes", "College German", SearchOperator::or())
    ->toList();

// * Results will contain Employee documents that have EITHER 'College' OR 'German'
//   in their 'Notes' field.
// * Search is case-insensitive.
from "Employees"
where search(Notes, "College German")

Search options

Search options allow to:

  • Negate a search criteria.
  • Specify the logical operator used between consecutive search calls.

Negate search:

/** @var array<Company> $companies */
$companies = $session
    ->query(Company::class)
    # Call 'not()' to negate the next search call
    ->not()
    ->search("Address", "USA")
    ->toList();

// * Results will contain Company documents are NOT located in 'USA'
// * Search is case-insensitive
/** @var array<Company> $companies */
$companies = $session->advanced()
    ->documentQuery(Company::class)
    ->openSubclause()
    // Call 'not()' to negate the next search call
    ->not()
    ->search("Address", "USA")
    ->closeSubclause()
    ->toList();

// * Results will contain Company documents are NOT located in 'USA'
// * Search is case-insensitive
from "Companies"
where (exists(Address) and not search(Address, "USA"))

Default behavior between search calls:

  • By default, the logical operator between consecutive search methods is OR.

/** @var array<Company> $companies */
$companies = $session
    ->query(Company::class)
    ->whereEquals("Contact.Title", "Owner")
    // Operator AND will be used with previous 'Where' predicate
    ->search("Address.Country", "France")
    // Operator OR will be used between the two 'Search' calls by default
    ->search("Name", "Markets")
    ->toList();

// * Results will contain Company documents that have:
//   ('Owner' as the 'Contact.Title')
//   AND
//   (are located in 'France' OR have 'Markets' in their 'Name' field)
//
// * Search is case-insensitive
/** @var array<Company> $companies */
$companies = $session->advanced()
    ->documentQuery(Company::class)
    ->whereEquals("Contact.Title", "Owner")
    // Operator AND will be used with previous 'Where' predicate
    // Call 'openSubclause()' to open predicate block
    ->openSubclause()
    ->search("Address.Country", "France")
    // Operator OR will be used between the two 'Search' calls by default
    ->search("Name", "Markets")
    // Call 'closeSubclause()' to close predicate block
    ->closeSubclause()
    ->toList();

// * Results will contain Company documents that have:
//   ('Owner' as the 'Contact.Title')
//   AND
//   (are located in 'France' OR have 'Markets' in their 'Name' field)
//
// * Search is case-insensitive
from "Companies" 
where Contact.Title == "Owner" and
(search(Address.Country, "France") or search(Name, "Markets"))

AND search calls:

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    ->search("Notes", "French")
    // Call 'AndAlso' so that operator AND will be used with previous 'search' call
    ->andAlso()
    ->search("Title", "Manager")
    ->toList();

// * Results will contain Employee documents that have:
//   ('French' in their 'Notes' field)
//   AND
//   ('Manager' in their 'Title' field)
//
// * Search is case-insensitive
/** @var array<Employee> $employees */
$employees = $session->advanced()
    ->documentQuery(Employee::class)
    ->search("Notes", "French")
    // Call 'andAlso()' so that operator AND will be used with previous 'search' call
    ->andAlso()
    ->search("Title", "Manger")
    ->toList();

// * Results will contain Employee documents that have:
//   ('French' in their 'Notes' field)
//   AND
//   ('Manager' in their 'Title' field)
//
// * Search is case-insensitive
from "Employees" 
where search(Notes, "French") and search(Title, "Manager")

Use options as bit flags:

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    ->search("Notes", "French")
    // Call 'andAlso()' so that operator AND will be used with previous 'search' call
    ->andAlso()
    ->openSubclause()
    // Call 'not()' to negate the next search call
    ->not()
    ->search("Title", "Manager")
    ->closeSubclause()
    ->toList();

// * Results will contain Employee documents that have:
//   ('French' in their 'Notes' field)
//   AND
//   (do NOT have 'Manager' in their 'Title' field)
//
// * Search is case-insensitive
/** @var array<Employee> $employees */
$employees = $session->advanced()
    ->documentQuery(Employee::class)
    ->search("Notes", "French")
    // Call 'andAlso()' so that operator AND will be used with previous 'search' call
    ->andAlso()
    ->openSubclause()
    // Call 'not()' to negate the next search call
    ->not()
    ->search("Title", "Manager")
    ->closeSubclause()
    ->toList();

// * Results will contain Employee documents that have:
//   ('French' in their 'Notes' field)
//   AND
//   (do NOT have 'Manager' in their 'Title' field)
//
// * Search is case-insensitive
from "Employees"
where search(Notes, "French") and
(exists(Title) and not search(Title, "Manager"))

Using wildcards

  • Wildcards can be used to replace:

    • Prefix of a searched term
    • Postfix of a searched term
    • Both prefix & postfix
  • Note:

    • Searching with a wildcard as the prefix of the term (e.g. *text) is not advised as it will cause the server to perform a full index scan.

    • Instead, consider using a static-index that indexes the field in reverse order
      and then query with a wildcard as the postfix, which is much faster.

/** @var array<Employee> $employees */
$employees = $session
    ->query(Employee::class)
    // Use '*' to replace one or more characters
    ->search("Notes", "art*")
    ->search("Notes", "*logy")
    ->search("Notes", "*mark*")
    ->ToList();

// Results will contain Employee documents that have in their 'Notes' field:
// (terms that start with 'art')  OR
// (terms that end with 'logy') OR
// (terms that have the text 'mark' in the middle)
//
// * Search is case-insensitive
/** @var array<Employee> $employees */
$employees = $session->advanced()
    ->documentQuery(Employee::class)
    // Use '*' to replace one ore more characters
    ->search("Notes", "art*")
    ->search("Notes", "*logy")
    ->search("Notes", "*mark*")
    ->toList();

// Results will contain Employee documents that have in their 'Notes' field:
// (terms that start with 'art')  OR
// (terms that end with 'logy') OR
// (terms that have the text 'mark' in the middle)
//
// * Search is case-insensitive
from "Employees" where
search(Notes, "art*") or
search(Notes, "*logy") or
search(Notes, "*mark*")

Syntax

public function search(string $fieldName, string $searchTerms, ?SearchOperator $operator = null): DocumentQueryInterface;
Parameter Type Description
$fieldName string Name of the searched field.
$searchTerms string A string containing the term or terms (separated by spaces) to search for.
$operator ?SearchOperator Logical operator to use between multiple terms in the same Search method.
Can be: SearchOperator::or or SearchOperator::and
Default: SearchOperator::or
Return Type Description
DocumentQueryInterface Query results