Skip to content

Commit 134feee

Browse files
committed
PCBC-557: Better FTS example
Change-Id: I33a296f745f79fdcfdf0e0293a4ff0f726f3940d Reviewed-on: http://review.couchbase.org/97861 Tested-by: Build Bot <[email protected]> Reviewed-by: Sergey Avseyev <[email protected]>
1 parent 754807a commit 134feee

File tree

2 files changed

+213
-3
lines changed

2 files changed

+213
-3
lines changed

examples/search/search.php

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
<?php
2+
3+
/**
4+
The example assumes the existence of "travel-sample" bucket and three
5+
specific Full Text Indexes, defined for it. These are:
6+
- "travel-sample-index-unstored": Uses only the default settings.
7+
- "travel-sample-index-stored": Uses default settings, with one exception:
8+
dynamic fields are stored, for the whole index.
9+
- "travel-sample-index-hotel-description": Indexes only the description
10+
fields of hotel documents, and disables the default type mapping. The index
11+
has a custom analyzer named myUnicodeAnalyzer defined on it: the analyzer's
12+
main characteristic is that it uses the unicode tokenizer.
13+
*/
14+
15+
use \Couchbase\Cluster;
16+
use \Couchbase\Bucket;
17+
use \Couchbase\SearchQuery;
18+
19+
function printResult($label, $resultObject) {
20+
echo("\n");
21+
echo("= = = = = = = = = = = = = = = = = = = = = = =\n");
22+
echo("= = = = = = = = = = = = = = = = = = = = = = =\n");
23+
echo("\n");
24+
echo($label);
25+
echo(' (total hits: ' . $resultObject->metrics['total_hits'] . ')');
26+
echo("\n");
27+
28+
foreach ($resultObject->hits as $row) {
29+
echo("id=" . $row->id . ", score=" . $row->score);
30+
if (property_exists($row, 'fields')) {
31+
echo(", fields=" . json_encode($row->fields));
32+
}
33+
if (property_exists($row, 'locations')) {
34+
echo(", locations=" . json_encode($row->locations));
35+
}
36+
if (property_exists($row, 'fragments')) {
37+
echo(", fragments=" . json_encode($row->fragments));
38+
}
39+
echo("\n");
40+
}
41+
}
42+
43+
// Simple Text Query on a single word, targeting an index with dynamic fields
44+
// unstored.
45+
function simpleTextQuery(Bucket $bucket) {
46+
$indexName = "travel-sample-index-unstored";
47+
$query = new SearchQuery($indexName,
48+
SearchQuery::match("swanky"));
49+
$query->limit(10);
50+
$result = $bucket->query($query);
51+
printResult("Simple Text Query", $result);
52+
}
53+
54+
// Simple Text Query on Stored Field, specifying the field to be searched;
55+
// targeting an index with dynamic fields stored, to ensure that field-content
56+
// is included in the return object.
57+
function simpleTextQueryOnStoredField(Bucket $bucket) {
58+
$indexName = "travel-sample-index-stored";
59+
$query = new SearchQuery($indexName,
60+
SearchQuery::match("MDG")->field("destinationairport"));
61+
$query->limit(10)->highlight(SearchQuery::HIGHLIGHT_HTML);
62+
$result = $bucket->query($query);
63+
printResult("Simple Text Query on Stored Field", $result);
64+
}
65+
66+
// Simple Text Query on Non-Default Index, specifying an index that consists
67+
// only of content derived from a specific field from a specific document-type.
68+
function simpleTextQueryOnNonDefaultIndex(Bucket $bucket) {
69+
$indexName = "travel-sample-index-hotel-description";
70+
$query = new SearchQuery($indexName,
71+
SearchQuery::match("swanky"));
72+
$query->limit(10);
73+
$result = $bucket->query($query);
74+
printResult("Simple Text Query on Non-Default Index", $result);
75+
}
76+
77+
// Match Query with Facet, showing how query-results can be displayed either by
78+
// row or by hits; and demonstrating use of a facet, which provides
79+
// aggregation-data.
80+
function textQueryOnStoredFieldWithFacet(Bucket $bucket) {
81+
$indexName = "travel-sample-index-stored";
82+
$query = new SearchQuery($indexName,
83+
SearchQuery::match("La Rue Saint Denis!!")->field("reviews.content"));
84+
$query->limit(10)->highlight(SearchQuery::HIGHLIGHT_HTML);
85+
$query->addFacet('Countries Referenced', SearchQuery::termFacet('country', 5));
86+
$result = $bucket->query($query);
87+
printResult("Match Query with Facet, Result by Row", $result);
88+
89+
echo("Match Query with Facet, Result by facet:\n");
90+
echo(json_encode($result->facets) . "\n");
91+
}
92+
93+
// DocId Query, showing results of a query on two document IDs.
94+
function docIdQueryMethod(Bucket $bucket) {
95+
$indexName = "travel-sample-index-unstored";
96+
$query = new SearchQuery($indexName,
97+
SearchQuery::docId("hotel_26223", "hotel_28960"));
98+
$result = $bucket->query($query);
99+
printResult("DocId Query", $result);
100+
}
101+
102+
// Unanalyzed Term Query with Fuzziness Level, demonstrating how to query on a
103+
// term with no analysis. Zero fuzziness is specified, to ensure that matches
104+
// are exact. With a fuzziness factor of 2, allowing partial matches to be made.
105+
function unAnalyzedTermQuery(Bucket $bucket, int $fuzzinessLevel) {
106+
$indexName = "travel-sample-index-stored";
107+
$query = new SearchQuery($indexName,
108+
SearchQuery::term("sushi")->field("reviews.content")->fuzziness($fuzzinessLevel));
109+
$query->limit(50)->highlight(SearchQuery::HIGHLIGHT_HTML);
110+
$result = $bucket->query($query);
111+
printResult("Unanalyzed Term Query with Fuzziness Level of " . $fuzzinessLevel . ":", $result);
112+
}
113+
114+
// Match Phrase Query, using Analysis, for searching on a phrase.
115+
function matchPhraseQueryOnStoredField(Bucket $bucket) {
116+
$indexName = "travel-sample-index-stored";
117+
$query = new SearchQuery($indexName,
118+
SearchQuery::matchPhrase("Eiffel Tower")->field("description"));
119+
$query->limit(10)->highlight(SearchQuery::HIGHLIGHT_HTML);
120+
$result = $bucket->query($query);
121+
printResult("Match Phrase Query, using Analysis", $result);
122+
}
123+
124+
// Phrase Query, without Analysis, for searching on a phrase without analysis supported.
125+
function unAnalyzedPhraseQuery(Bucket $bucket) {
126+
$indexName = "travel-sample-index-stored";
127+
$query = new SearchQuery($indexName,
128+
SearchQuery::phrase("dorm", "rooms")->field("description"));
129+
$query->limit(10)->highlight(SearchQuery::HIGHLIGHT_HTML);
130+
$result = $bucket->query($query);
131+
printResult("Phrase Query, without Analysis", $result);
132+
}
133+
134+
// Conjunction Query, whereby two separate queries are defined and then run as
135+
// part of the search, with only the matches returned by both included in the
136+
// result-object.
137+
function conjunctionQuery(Bucket $bucket) {
138+
$indexName = "travel-sample-index-stored";
139+
$firstQuery = SearchQuery::match("La Rue Saint Denis!!")->field("reviews.content");
140+
$secondQuery = SearchQuery::match("boutique")->field("description");
141+
$query = new SearchQuery($indexName,
142+
SearchQuery::conjuncts($firstQuery, $secondQuery));
143+
$query->limit(10)->highlight(SearchQuery::HIGHLIGHT_HTML);
144+
$result = $bucket->query($query);
145+
printResult("Conjunction Query", $result);
146+
}
147+
148+
// Query String Query, showing how a query string is specified as search-input.
149+
function queryStringQuery(Bucket $bucket) {
150+
$indexName = "travel-sample-index-unstored";
151+
$query = new SearchQuery($indexName,
152+
SearchQuery::queryString("description: Imperial"));
153+
$query->limit(10);
154+
$result = $bucket->query($query);
155+
printResult("Query String Query", $result);
156+
}
157+
158+
// Wild Card Query, whereby a wildcard is used in the string submitted for the
159+
// search.
160+
function wildCardQuery(Bucket $bucket) {
161+
$indexName = "travel-sample-index-stored";
162+
$query = new SearchQuery($indexName,
163+
SearchQuery::wildcard("bouti*ue")->field("description"));
164+
$query->limit(10)->highlight(SearchQuery::HIGHLIGHT_HTML);
165+
$result = $bucket->query($query);
166+
printResult("Wild Card Query", $result);
167+
}
168+
169+
// Numeric Range Query, whereby minimum and maximum numbers are specified, and
170+
// matches within the range returned.
171+
function numericRangeQuery(Bucket $bucket) {
172+
$indexName = "travel-sample-index-unstored";
173+
$query = new SearchQuery($indexName,
174+
SearchQuery::numericRange()->min(10100)->max(10200)->field("id"));
175+
$query->limit(10);
176+
$result = $bucket->query($query);
177+
printResult("Numeric Range Query", $result);
178+
}
179+
180+
// Regexp Query, whereby a regular expression is submitted, to generate the
181+
// conditions for successful matches.
182+
function regexpQuery(Bucket $bucket) {
183+
$indexName = "travel-sample-index-stored";
184+
$query = new SearchQuery($indexName,
185+
SearchQuery::regexp("[a-z]")->field("description"));
186+
$query->limit(10)->highlight(SearchQuery::HIGHLIGHT_HTML);
187+
$result = $bucket->query($query);
188+
printResult("Regexp Query", $result);
189+
}
190+
191+
$cluster = new Cluster('couchbase://localhost');
192+
$cluster->authenticateAs('Administrator', 'password');
193+
$bucket = $cluster->openBucket('travel-sample');
194+
195+
simpleTextQuery($bucket);
196+
simpleTextQueryOnStoredField($bucket);
197+
simpleTextQueryOnNonDefaultIndex($bucket);
198+
textQueryOnStoredFieldWithFacet($bucket);
199+
docIdQueryMethod($bucket);
200+
unAnalyzedTermQuery($bucket, 0);
201+
unAnalyzedTermQuery($bucket, 2);
202+
matchPhraseQueryOnStoredField($bucket);
203+
unAnalyzedPhraseQuery($bucket);
204+
conjunctionQuery($bucket);
205+
queryStringQuery($bucket);
206+
wildCardQuery($bucket);
207+
numericRangeQuery($bucket);
208+
regexpQuery($bucket);

src/couchbase/search_query.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ PHP_METHOD(SearchQuery, highlight)
696696
int rv, num_args = 0;
697697
pcbc_str_arg_size style_len;
698698

699-
rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s+", &style, &style_len, &args, &num_args);
699+
rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s*", &style, &style_len, &args, &num_args);
700700
if (rv == FAILURE) {
701701
return;
702702
}
@@ -801,7 +801,9 @@ PHP_METHOD(SearchQuery, jsonSerialize)
801801
ADD_ASSOC_ZVAL_EX(return_value, "highlight", PCBC_P(highlight));
802802

803803
ADD_ASSOC_STRING(PCBC_P(highlight), "style", obj->highlight_style);
804-
ADD_ASSOC_ZVAL_EX(PCBC_P(highlight), "fields", PCBC_P(obj->highlight_fields));
804+
if (php_array_count(PCBC_P(obj->highlight_fields)) > 0) {
805+
ADD_ASSOC_ZVAL_EX(PCBC_P(highlight), "fields", PCBC_P(obj->highlight_fields));
806+
}
805807
PCBC_ADDREF_P(PCBC_P(obj->highlight_fields));
806808
}
807809
if (!Z_ISUNDEF(obj->query_part)) {
@@ -907,7 +909,7 @@ ZEND_BEGIN_ARG_INFO_EX(ai_SearchQuery_sort, 0, 0, 1)
907909
PCBC_ARG_VARIADIC_INFO(0, sort)
908910
ZEND_END_ARG_INFO()
909911

910-
ZEND_BEGIN_ARG_INFO_EX(ai_SearchQuery_highlight, 0, 0, 2)
912+
ZEND_BEGIN_ARG_INFO_EX(ai_SearchQuery_highlight, 0, 0, 1)
911913
ZEND_ARG_INFO(0, style)
912914
PCBC_ARG_VARIADIC_INFO(0, fields)
913915
ZEND_END_ARG_INFO()

0 commit comments

Comments
 (0)