A newer version of this documentation is available.

View Latest

Full Text Search (FTS) Using the PHP SDK with Couchbase Server

You can use the Full Text Search service (FTS) to create queryable full-text indexes in Couchbase Server.

Couchbase offers Full-text search support, allowing you to search for documents that contain certain words or phrases. In the PHP SDK you can search full-text indexes by using the CouchbaseBucket.query(CouchbaseSearchQuery) API.

The FTS feature is a developer preview in Couchbase Server 4.5. As such, the support in the SDK is still uncomitted and the API is subject to change (although no major changes are expected as of this writing).

Querying a FTS index through the PHP client is performed through the CouchbaseBucket.query(CouchbaseSearchQuery) method, providing a CouchbaseSearchQuery. Building a CouchbaseSearchQuery takes two parameters, the index name to query and the actual search query itself. In this way, it is a sort of a statement. Additional search options may be specified by using the CouchbaseSearchQuery as a builder, chaining setters for each relevant option.

Depending on the third argument, this method returns an object of which the hits property represents array of either stdClass instances or plain arrays. Each of the entries represent a hit for the query and contains the index, id and score properties respectively, identifying the exact FTS index that returned the hit, the id of the document that matched and a decimal score for the match. It also contains optional sections depending on the request and the availability of all relevant settings in the FTS mapping. Those are in the explanation (an explanation of the plan followed by the FTS index to execute the query), locations (a map-like listing of the location of all matching terms inside each relevant field that was queried), fragments (a map-like listing of occurrences of the search terms in each field, with the context of the terms) and fields (a map of the complete value of each requested field). Most of these need an index configured to store the data of a searched field. In addition to hits property, any result also contains a status for the request, some execution metrics and facets if facets have been requested.

$cluster = new CouchbaseCluster('couchbase://localhost');
$bucket = $cluster->openBucket("travel-sample");
$fts = CouchbaseSearchQuery::match("term");
$result = $bucket->query(new CouchbaseSearchQuery("travel-search", $fts));
foreach ($result->hits as $search_hit) {
  var_dump($search_hit);
}

Query Types

There are many different flavors of search queries, and each can be constructed through static factory methods in the CouchbaseSearchQuery class. All of these types derive from the CouchbaseAbstractSearchQuery. It contains query classes corresponding to those listed in the FTS generic documentation.

It is important to distinguish between query options and general search options. Some options affect the search process in general (such as the limit, indicating how many results to return) while others only affect a specific query (such as fuzziness for a given query). Because multiple queries can be combined in a single search operation, query specific options can be specified only in the query object itself, while search options are specified at the level of the CouchbaseSearchQuery class, using builder methods.

$cluster = new CouchbaseCluster('couchbase://localhost');
$bucket = $cluster->openBucket("travel-sample");
$fts = CouchbaseSearchQuery::match("term");
$query = new CouchbaseSearchQuery("travel-search", $fts);
//search options:
//will show value for activity and country fields
$query->fields(array("activity", "country"))
       //will have max 3 hits
       ->limit(3);
$result = $bucket->query($query);
foreach ($result->hits as $search_hit) {
  var_dump($search_hit);
}

Here’s some sample output for the previous query against the travel-sample dataset:

object(stdClass)#6 (5) {
  ["index"]=>
  string(39) "travel-sample_683e328089809988_a4a23588"
  ["id"]=>
  string(13) "landmark_4955"
  ["score"]=>
  float(0.8133278848105)
  ["locations"]=>
  object(stdClass)#7 (1) {
    ["content"]=>
    object(stdClass)#8 (1) {
      ["term"]=>
      array(1) {
        [0]=>
        object(stdClass)#9 (4) {
          ["pos"]=>
          int(24)
          ["start"]=>
          int(159)
          ["end"]=>
          int(163)
          ["array_positions"]=>
          NULL
        }
      }
    }
  }
  ["fields"]=>
  object(stdClass)#10 (2) {
    ["activity"]=>
    string(5) "drink"
    ["country"]=>
    string(14) "United Kingdom"
  }
}
object(stdClass)#11 (5) {
  ["index"]=>
  string(39) "travel-sample_683e328089809988_37fdcf3c"
  ["id"]=>
  string(14) "landmark_15854"
  ["score"]=>
  float(0.74464445323204)
  ["locations"]=>
  object(stdClass)#12 (1) {
    ["content"]=>
    object(stdClass)#13 (1) {
      ["term"]=>
      array(1) {
        [0]=>
        object(stdClass)#14 (4) {
          ["pos"]=>
          int(21)
          ["start"]=>
          int(137)
          ["end"]=>
          int(141)
          ["array_positions"]=>
          NULL
        }
      }
    }
  }
  ["fields"]=>
  object(stdClass)#15 (2) {
    ["activity"]=>
    string(3) "see"
    ["country"]=>
    string(14) "United Kingdom"
  }
}
object(stdClass)#16 (5) {
  ["index"]=>
  string(39) "travel-sample_683e328089809988_9e13fa43"
  ["id"]=>
  string(14) "landmark_16265"
  ["score"]=>
  float(0.68760768406444)
  ["locations"]=>
  object(stdClass)#17 (1) {
    ["content"]=>
    object(stdClass)#18 (1) {
      ["term"]=>
      array(1) {
        [0]=>
        object(stdClass)#19 (4) {
          ["pos"]=>
          int(41)
          ["start"]=>
          int(209)
          ["end"]=>
          int(213)
          ["array_positions"]=>
          NULL
        }
      }
    }
  }
  ["fields"]=>
  object(stdClass)#20 (2) {
    ["activity"]=>
    string(3) "see"
    ["country"]=>
    string(14) "United Kingdom"
  }
}

Query Facets

Query facets may also be added to the general search parameters by using the addFacet($name, $facet) builder method on CouchbaseSearchQuery. You can create facet queries by instantiating facets through factory methods in the CouchbaseSearchFacet class.

$cluster = new CouchbaseCluster('couchbase://localhost');
$bucket = $cluster->openBucket("travel-sample");
$fts = CouchbaseSearchQuery::match("term");
$query = new CouchbaseSearchQuery("travel-search", $fts);
//search options:
//will show value for activity and country fields
$query->fields(array("activity", "country"))
       //will have max 3 hits
       ->limit(3)
       //will have a "countries" facet on the top 3 countries in terms of hits
       ->addFacet("countries", CouchbaseSearchFacet::term("country", 3));

$result = $bucket->query($query);
var_dump($result->facets);

Here is the facet part of the result from the query above:

array(1) {
  ["countries"]=>
  array(5) {
    ["field"]=>
    string(7) "country"
    ["total"]=>
    int(42)
    ["missing"]=>
    int(0)
    ["other"]=>
    int(0)
    ["terms"]=>
    array(3) {
      [0]=>
      array(2) {
        ["term"]=>
        string(6) "united"
        ["count"]=>
        int(21)
      }
      [1]=>
      array(2) {
        ["term"]=>
        string(7) "kingdom"
        ["count"]=>
        int(14)
      }
      [2]=>
      array(2) {
        ["term"]=>
        string(6) "states"
        ["count"]=>
        int(7)
      }
    }
  }
}