0
# Search Operations
1
2
Advanced full-text search capabilities with support for complex queries, faceting, sorting, and highlighting. Enables powerful text search across document collections using Couchbase's integrated search service.
3
4
## Capabilities
5
6
### Search Query Execution
7
8
Execute full-text search queries with various options and result formatting.
9
10
```python { .api }
11
class Cluster:
12
def search_query(self, index: str, query: SearchQuery, options: SearchOptions = None) -> SearchResult:
13
"""
14
Execute full-text search query.
15
16
Args:
17
index (str): Search index name
18
query (SearchQuery): Search query object
19
options (SearchOptions, optional): Search execution options
20
21
Returns:
22
SearchResult: Search results iterator
23
24
Raises:
25
SearchException: If search execution fails
26
IndexNotFoundException: If search index doesn't exist
27
"""
28
29
class SearchOptions:
30
def __init__(self, timeout: timedelta = None,
31
skip: int = None,
32
limit: int = None,
33
explain: bool = False,
34
highlight: HighlightStyle = None,
35
fields: List[str] = None,
36
facets: Dict[str, Facet] = None,
37
sort: List[Sort] = None,
38
scan_consistency: SearchScanConsistency = None,
39
consistent_with: MutationState = None,
40
raw: Dict[str, Any] = None):
41
"""
42
Search query execution options.
43
44
Args:
45
timeout (timedelta, optional): Search timeout
46
skip (int, optional): Number of results to skip
47
limit (int, optional): Maximum results to return
48
explain (bool): Include score explanation
49
highlight (HighlightStyle, optional): Result highlighting
50
fields (List[str], optional): Fields to return
51
facets (Dict[str, Facet], optional): Facet definitions
52
sort (List[Sort], optional): Result sorting
53
scan_consistency (SearchScanConsistency, optional): Consistency level
54
consistent_with (MutationState, optional): Consistency token
55
raw (Dict[str, Any], optional): Raw search options
56
"""
57
```
58
59
### Search Query Types
60
61
Various search query types for different search patterns.
62
63
```python { .api }
64
class SearchQuery:
65
"""Base class for all search queries."""
66
67
@staticmethod
68
def match(match: str) -> MatchQuery:
69
"""
70
Create match query for text search.
71
72
Args:
73
match (str): Text to match
74
75
Returns:
76
MatchQuery: Match query instance
77
"""
78
79
@staticmethod
80
def term(term: str) -> TermQuery:
81
"""
82
Create term query for exact matches.
83
84
Args:
85
term (str): Exact term to match
86
87
Returns:
88
TermQuery: Term query instance
89
"""
90
91
@staticmethod
92
def phrase(terms: List[str]) -> PhraseQuery:
93
"""
94
Create phrase query for exact phrase matching.
95
96
Args:
97
terms (List[str]): Terms in phrase
98
99
Returns:
100
PhraseQuery: Phrase query instance
101
"""
102
103
@staticmethod
104
def prefix(prefix: str) -> PrefixQuery:
105
"""
106
Create prefix query.
107
108
Args:
109
prefix (str): Prefix to match
110
111
Returns:
112
PrefixQuery: Prefix query instance
113
"""
114
115
@staticmethod
116
def wildcard(wildcard: str) -> WildcardQuery:
117
"""
118
Create wildcard query with * and ? patterns.
119
120
Args:
121
wildcard (str): Wildcard pattern
122
123
Returns:
124
WildcardQuery: Wildcard query instance
125
"""
126
127
@staticmethod
128
def regex(regexp: str) -> RegexQuery:
129
"""
130
Create regular expression query.
131
132
Args:
133
regexp (str): Regular expression pattern
134
135
Returns:
136
RegexQuery: Regex query instance
137
"""
138
139
@staticmethod
140
def numeric_range(min_val: float = None, max_val: float = None) -> NumericRangeQuery:
141
"""
142
Create numeric range query.
143
144
Args:
145
min_val (float, optional): Minimum value
146
max_val (float, optional): Maximum value
147
148
Returns:
149
NumericRangeQuery: Numeric range query instance
150
"""
151
152
@staticmethod
153
def date_range(start: datetime = None, end: datetime = None) -> DateRangeQuery:
154
"""
155
Create date range query.
156
157
Args:
158
start (datetime, optional): Start date
159
end (datetime, optional): End date
160
161
Returns:
162
DateRangeQuery: Date range query instance
163
"""
164
165
@staticmethod
166
def geo_distance(location: GeoPoint, distance: str) -> GeoDistanceQuery:
167
"""
168
Create geographic distance query.
169
170
Args:
171
location (GeoPoint): Center point
172
distance (str): Distance (e.g., "10km", "5mi")
173
174
Returns:
175
GeoDistanceQuery: Geographic distance query instance
176
"""
177
178
@staticmethod
179
def geo_bounding_box(top_left: GeoPoint, bottom_right: GeoPoint) -> GeoBoundingBoxQuery:
180
"""
181
Create geographic bounding box query.
182
183
Args:
184
top_left (GeoPoint): Top-left corner
185
bottom_right (GeoPoint): Bottom-right corner
186
187
Returns:
188
GeoBoundingBoxQuery: Geographic bounding box query instance
189
"""
190
191
@staticmethod
192
def boolean() -> BooleanQuery:
193
"""
194
Create boolean combination query.
195
196
Returns:
197
BooleanQuery: Boolean query instance
198
"""
199
200
@staticmethod
201
def match_all() -> MatchAllQuery:
202
"""
203
Create match-all query.
204
205
Returns:
206
MatchAllQuery: Match all query instance
207
"""
208
209
@staticmethod
210
def match_none() -> MatchNoneQuery:
211
"""
212
Create match-none query.
213
214
Returns:
215
MatchNoneQuery: Match none query instance
216
"""
217
```
218
219
### Query Configuration
220
221
Configure individual query types with specific options.
222
223
```python { .api }
224
class MatchQuery(SearchQuery):
225
def field(self, field: str) -> MatchQuery:
226
"""Specify field to search."""
227
228
def analyzer(self, analyzer: str) -> MatchQuery:
229
"""Set text analyzer."""
230
231
def boost(self, boost: float) -> MatchQuery:
232
"""Set query boost factor."""
233
234
def prefix_length(self, prefix_length: int) -> MatchQuery:
235
"""Set prefix length for fuzzy matching."""
236
237
def fuzziness(self, fuzziness: int) -> MatchQuery:
238
"""Set fuzziness level."""
239
240
def operator(self, operator: MatchOperator) -> MatchQuery:
241
"""Set match operator (AND/OR)."""
242
243
class TermQuery(SearchQuery):
244
def field(self, field: str) -> TermQuery:
245
"""Specify field to search."""
246
247
def boost(self, boost: float) -> TermQuery:
248
"""Set query boost factor."""
249
250
class NumericRangeQuery(SearchQuery):
251
def field(self, field: str) -> NumericRangeQuery:
252
"""Specify numeric field."""
253
254
def min(self, min_val: float, inclusive: bool = True) -> NumericRangeQuery:
255
"""Set minimum value."""
256
257
def max(self, max_val: float, inclusive: bool = True) -> NumericRangeQuery:
258
"""Set maximum value."""
259
260
def boost(self, boost: float) -> NumericRangeQuery:
261
"""Set query boost factor."""
262
263
class BooleanQuery(SearchQuery):
264
def must(self, query: SearchQuery) -> BooleanQuery:
265
"""Add must clause (AND)."""
266
267
def should(self, query: SearchQuery) -> BooleanQuery:
268
"""Add should clause (OR)."""
269
270
def must_not(self, query: SearchQuery) -> BooleanQuery:
271
"""Add must not clause (NOT)."""
272
273
def boost(self, boost: float) -> BooleanQuery:
274
"""Set query boost factor."""
275
```
276
277
### Faceting
278
279
Aggregate search results by categories for navigation and filtering.
280
281
```python { .api }
282
class Facet:
283
"""Base class for all facets."""
284
285
@staticmethod
286
def term(field: str, size: int = 10) -> TermFacet:
287
"""
288
Create term facet for categorical aggregation.
289
290
Args:
291
field (str): Field to facet on
292
size (int): Maximum number of facet terms
293
294
Returns:
295
TermFacet: Term facet instance
296
"""
297
298
@staticmethod
299
def date_range(field: str, *ranges: DateRange) -> DateRangeFacet:
300
"""
301
Create date range facet.
302
303
Args:
304
field (str): Date field to facet on
305
*ranges: Date range definitions
306
307
Returns:
308
DateRangeFacet: Date range facet instance
309
"""
310
311
@staticmethod
312
def numeric_range(field: str, *ranges: NumericRange) -> NumericRangeFacet:
313
"""
314
Create numeric range facet.
315
316
Args:
317
field (str): Numeric field to facet on
318
*ranges: Numeric range definitions
319
320
Returns:
321
NumericRangeFacet: Numeric range facet instance
322
"""
323
324
class DateRange:
325
def __init__(self, name: str, start: datetime = None, end: datetime = None):
326
"""Date range for faceting."""
327
328
class NumericRange:
329
def __init__(self, name: str, min_val: float = None, max_val: float = None):
330
"""Numeric range for faceting."""
331
```
332
333
### Result Sorting
334
335
Sort search results by various criteria.
336
337
```python { .api }
338
class Sort:
339
"""Base class for all sort options."""
340
341
@staticmethod
342
def score() -> SortScore:
343
"""Sort by relevance score (default)."""
344
345
@staticmethod
346
def id() -> SortId:
347
"""Sort by document ID."""
348
349
@staticmethod
350
def field(field: str) -> SortField:
351
"""Sort by field value."""
352
353
@staticmethod
354
def geo_distance(location: GeoPoint, field: str) -> SortGeoDistance:
355
"""Sort by geographic distance."""
356
357
class SortField(Sort):
358
def desc(self) -> SortField:
359
"""Sort in descending order."""
360
361
def type(self, type: str) -> SortField:
362
"""Set field type (auto, string, number, date)."""
363
364
def mode(self, mode: str) -> SortField:
365
"""Set sort mode (min, max, default)."""
366
367
def missing(self, missing: str) -> SortField:
368
"""Set behavior for missing values (first, last)."""
369
```
370
371
## Search Results
372
373
```python { .api }
374
class SearchResult:
375
def __iter__(self) -> Iterator[SearchRow]:
376
"""Iterate over search result rows."""
377
378
def metadata(self) -> SearchMetaData:
379
"""Get search execution metadata."""
380
381
def rows(self) -> List[SearchRow]:
382
"""Get all result rows as list."""
383
384
def facets(self) -> Dict[str, SearchFacetResult]:
385
"""Get facet results."""
386
387
class SearchRow:
388
@property
389
def index(self) -> str:
390
"""Search index name."""
391
392
@property
393
def id(self) -> str:
394
"""Document ID."""
395
396
@property
397
def score(self) -> float:
398
"""Relevance score."""
399
400
@property
401
def explanation(self) -> dict:
402
"""Score explanation (if requested)."""
403
404
@property
405
def locations(self) -> dict:
406
"""Match locations."""
407
408
@property
409
def fragments(self) -> dict:
410
"""Highlighted fragments."""
411
412
@property
413
def fields(self) -> dict:
414
"""Retrieved field values."""
415
416
class SearchMetaData:
417
@property
418
def metrics(self) -> SearchMetrics:
419
"""Search execution metrics."""
420
421
@property
422
def errors(self) -> Dict[str, str]:
423
"""Search execution errors."""
424
425
class SearchMetrics:
426
@property
427
def took(self) -> timedelta:
428
"""Search execution time."""
429
430
@property
431
def total_hits(self) -> int:
432
"""Total number of matching documents."""
433
434
@property
435
def max_score(self) -> float:
436
"""Maximum relevance score."""
437
438
@property
439
def success_partition_count(self) -> int:
440
"""Number of successful partitions."""
441
442
@property
443
def error_partition_count(self) -> int:
444
"""Number of failed partitions."""
445
```
446
447
## Usage Examples
448
449
### Basic Search Operations
450
451
```python
452
from couchbase.search import SearchQuery, SearchOptions
453
454
# Simple text search
455
query = SearchQuery.match("hotel california")
456
result = cluster.search_query("travel-search", query)
457
458
for row in result:
459
print(f"Document {row.id}: Score {row.score}")
460
if 'name' in row.fields:
461
print(f" Name: {row.fields['name']}")
462
463
# Get search metadata
464
metadata = result.metadata()
465
print(f"Search took: {metadata.metrics.took}")
466
print(f"Total hits: {metadata.metrics.total_hits}")
467
```
468
469
### Complex Query Construction
470
471
```python
472
# Boolean query with multiple conditions
473
bool_query = SearchQuery.boolean()
474
bool_query.must(SearchQuery.match("luxury").field("description"))
475
bool_query.should(SearchQuery.term("hotel").field("type"))
476
bool_query.must_not(SearchQuery.term("closed").field("status"))
477
478
options = SearchOptions(limit=20, skip=0)
479
result = cluster.search_query("travel-search", bool_query, options)
480
```
481
482
### Range Queries
483
484
```python
485
# Numeric range query
486
price_query = SearchQuery.numeric_range(min_val=100, max_val=500).field("price")
487
488
# Date range query
489
from datetime import datetime
490
start_date = datetime(2023, 1, 1)
491
end_date = datetime(2023, 12, 31)
492
date_query = SearchQuery.date_range(start=start_date, end=end_date).field("created")
493
494
# Combine with boolean query
495
combined = SearchQuery.boolean()
496
combined.must(SearchQuery.match("luxury hotel"))
497
combined.must(price_query)
498
combined.must(date_query)
499
500
result = cluster.search_query("travel-search", combined)
501
```
502
503
### Geographic Search
504
505
```python
506
from couchbase.search import GeoPoint
507
508
# Geographic distance search
509
san_francisco = GeoPoint(37.7749, -122.4194)
510
geo_query = SearchQuery.geo_distance(san_francisco, "10km").field("location")
511
512
result = cluster.search_query("travel-search", geo_query)
513
514
for row in result:
515
print(f"Hotel {row.id} within 10km of SF")
516
```
517
518
### Faceted Search
519
520
```python
521
from couchbase.search import Facet
522
523
# Search with facets
524
facets = {
525
"type": Facet.term("type", size=10),
526
"price_ranges": Facet.numeric_range("price",
527
NumericRange("budget", max_val=100),
528
NumericRange("mid_range", min_val=100, max_val=300),
529
NumericRange("luxury", min_val=300)
530
),
531
"ratings": Facet.numeric_range("rating",
532
NumericRange("poor", max_val=2),
533
NumericRange("good", min_val=2, max_val=4),
534
NumericRange("excellent", min_val=4)
535
)
536
}
537
538
options = SearchOptions(facets=facets, limit=50)
539
result = cluster.search_query("travel-search", SearchQuery.match_all(), options)
540
541
# Process facet results
542
facet_results = result.facets()
543
for facet_name, facet_result in facet_results.items():
544
print(f"Facet: {facet_name}")
545
for term in facet_result.terms:
546
print(f" {term.term}: {term.count}")
547
```
548
549
### Sorting and Field Selection
550
551
```python
552
from couchbase.search import Sort
553
554
# Sort by multiple criteria
555
sort_options = [
556
Sort.field("rating").desc(),
557
Sort.field("price"),
558
Sort.score()
559
]
560
561
options = SearchOptions(
562
sort=sort_options,
563
fields=["name", "description", "price", "rating"], # Only return these fields
564
limit=20
565
)
566
567
result = cluster.search_query("travel-search", SearchQuery.match("hotel"), options)
568
569
for row in result:
570
print(f"{row.fields['name']}: ${row.fields['price']}, Rating: {row.fields['rating']}")
571
```
572
573
### Highlighting
574
575
```python
576
from couchbase.search import HighlightStyle
577
578
# Search with result highlighting
579
options = SearchOptions(
580
highlight=HighlightStyle.HTML,
581
fields=["name", "description"]
582
)
583
584
query = SearchQuery.match("luxury beachfront resort")
585
result = cluster.search_query("travel-search", query, options)
586
587
for row in result:
588
print(f"Document: {row.id}")
589
if row.fragments:
590
for field, fragments in row.fragments.items():
591
print(f" {field}: {' ... '.join(fragments)}")
592
```
593
594
### Search with Consistency
595
596
```python
597
from couchbase.mutation_state import MutationState
598
599
# Perform document update
600
doc = {"name": "New Luxury Hotel", "type": "hotel", "rating": 5}
601
mutation_result = collection.upsert("hotel::new", doc)
602
603
# Search with consistency
604
mutation_state = MutationState(mutation_result.mutation_token)
605
options = SearchOptions(consistent_with=mutation_state)
606
607
result = cluster.search_query("travel-search",
608
SearchQuery.match("New Luxury Hotel"),
609
options)
610
```
611
612
### Error Handling
613
614
```python
615
from couchbase.exceptions import SearchException, IndexNotFoundException
616
617
try:
618
result = cluster.search_query("nonexistent-index", SearchQuery.match_all())
619
for row in result:
620
print(row.id)
621
except IndexNotFoundException:
622
print("Search index not found")
623
except SearchException as e:
624
print(f"Search failed: {e}")
625
if hasattr(e, 'context'):
626
print(f"Error details: {e.context}")
627
```