0
# Searching
1
2
Search execution engine providing query processing, scoring, and result ranking. The search system supports both simple string queries and advanced programmatic query building with comprehensive query syntax including field restrictions, wildcards, fuzzy matching, and boolean operators.
3
4
## Capabilities
5
6
### Index Class
7
8
The built search index that provides query execution capabilities.
9
10
```javascript { .api }
11
/**
12
* Search index created by the Builder
13
*/
14
class Index {
15
/**
16
* Create a new Index instance (usually via Builder.build())
17
* @param {Object} attrs - Index attributes and configuration
18
*/
19
constructor(attrs);
20
21
/**
22
* Search the index using query string syntax
23
* @param {string} queryString - Query string with optional field restrictions, wildcards, etc.
24
* @returns {Array<Object>} - Array of search results with ref and score properties
25
*/
26
search(queryString);
27
28
/**
29
* Build queries programmatically for complex search logic
30
* @param {Function} builderFunction - Function that receives a Query builder instance
31
* @returns {Array<Object>} - Array of search results with ref and score properties
32
*/
33
query(builderFunction);
34
35
/**
36
* Serialize the index to JSON for storage or transmission
37
* @returns {Object} - Serialized index data
38
*/
39
toJSON();
40
41
/**
42
* Load an index from serialized JSON data
43
* @param {Object} serializedIndex - Previously serialized index
44
* @returns {lunr.Index} - Reconstructed index instance
45
*/
46
static load(serializedIndex);
47
}
48
49
/**
50
* Search result object
51
* @typedef {Object} SearchResult
52
* @property {string} ref - Document reference (as set by Builder.ref())
53
* @property {number} score - Relevance score (higher = more relevant)
54
* @property {Object} matchData - Optional match metadata and term positions
55
*/
56
```
57
58
**Usage Examples:**
59
60
```javascript
61
const lunr = require('lunr');
62
63
// Create index
64
const idx = lunr(function () {
65
this.ref('id');
66
this.field('title');
67
this.field('content');
68
69
this.add({ id: '1', title: 'JavaScript Guide', content: 'Learn JavaScript programming' });
70
this.add({ id: '2', title: 'Node.js Tutorial', content: 'Server-side JavaScript with Node.js' });
71
});
72
73
// Simple text search
74
const results = idx.search('javascript');
75
// Returns: [
76
// { ref: '1', score: 0.693 },
77
// { ref: '2', score: 0.405 }
78
// ]
79
80
// Field-specific search
81
const titleResults = idx.search('title:guide');
82
// Returns: [{ ref: '1', score: 1.099 }]
83
84
// Multiple terms
85
const multiResults = idx.search('javascript tutorial');
86
// Returns results containing either term, scored by relevance
87
```
88
89
### Query String Syntax
90
91
Comprehensive query string syntax for various search operations.
92
93
```javascript { .api }
94
/**
95
* Query string syntax patterns:
96
*
97
* Simple terms: "javascript node"
98
* Field restrictions: "title:guide", "content:tutorial"
99
* Required terms: "+javascript +tutorial" (both must be present)
100
* Prohibited terms: "-deprecated" (must not be present)
101
* Wildcards: "java*" (prefix), "*script" (suffix)
102
* Fuzzy search: "tutorial~1" (edit distance of 1)
103
* Term boosting: "important^10" (boost by factor of 10)
104
* Grouping: "+(javascript node.js) -deprecated"
105
*/
106
```
107
108
**Usage Examples:**
109
110
```javascript
111
// Field-specific searches
112
idx.search('title:javascript'); // Only search in title field
113
idx.search('title:guide content:node'); // Search title for "guide", content for "node"
114
115
// Boolean operators
116
idx.search('+javascript +tutorial'); // Must contain both terms
117
idx.search('+javascript -deprecated'); // Must contain "javascript", must not contain "deprecated"
118
idx.search('javascript OR node'); // Contains either term (default behavior)
119
120
// Wildcards
121
idx.search('java*'); // Terms starting with "java"
122
idx.search('*script'); // Terms ending with "script"
123
idx.search('*node*'); // Terms containing "node"
124
125
// Fuzzy matching
126
idx.search('javascrpt~1'); // Allow 1 character difference
127
idx.search('tutorial~2'); // Allow up to 2 character differences
128
129
// Term boosting
130
idx.search('javascript^10 tutorial'); // Boost "javascript" by factor of 10
131
idx.search('title:guide^5 content:node'); // Boost title matches
132
133
// Complex queries
134
idx.search('+(title:javascript^10 content:node) -deprecated~1');
135
```
136
137
### Programmatic Querying
138
139
Advanced programmatic query building for complex search logic.
140
141
```javascript { .api }
142
/**
143
* Programmatic query building through the query() method
144
* @param {Function} builderFunction - Function that receives a Query builder
145
*/
146
Index.prototype.query;
147
```
148
149
**Usage Examples:**
150
151
```javascript
152
// Programmatic query building
153
const results = idx.query(function (q) {
154
// Add required term
155
q.term('javascript', {
156
presence: lunr.Query.presence.REQUIRED,
157
boost: 10
158
});
159
160
// Add optional field-specific term
161
q.term('tutorial', {
162
fields: ['title'],
163
presence: lunr.Query.presence.OPTIONAL,
164
boost: 5
165
});
166
167
// Add prohibited term
168
q.term('deprecated', {
169
presence: lunr.Query.presence.PROHIBITED
170
});
171
});
172
173
// Wildcard queries
174
const wildcardResults = idx.query(function (q) {
175
q.term('java', {
176
wildcard: lunr.Query.wildcard.TRAILING, // "java*"
177
boost: 2
178
});
179
});
180
181
// Fuzzy queries with edit distance
182
const fuzzyResults = idx.query(function (q) {
183
q.term('javascrpt', {
184
editDistance: 1,
185
boost: 0.5 // Lower boost for fuzzy matches
186
});
187
});
188
```
189
190
### Index Serialization
191
192
Saving and loading indexes for persistent storage or network transmission.
193
194
```javascript { .api }
195
/**
196
* Serialize index to JSON
197
* @returns {Object} - Serialized index data
198
*/
199
Index.prototype.toJSON;
200
201
/**
202
* Load index from serialized data
203
* @param {Object} serializedIndex - Previously serialized index
204
* @returns {lunr.Index} - Reconstructed index instance
205
*/
206
Index.load;
207
```
208
209
**Usage Examples:**
210
211
```javascript
212
// Serialize index for storage
213
const idx = lunr(function () {
214
this.ref('id');
215
this.field('content');
216
this.add({ id: '1', content: 'Searchable content' });
217
});
218
219
const serialized = idx.toJSON();
220
221
// Save to localStorage
222
localStorage.setItem('searchIndex', JSON.stringify(serialized));
223
224
// Save to file (Node.js)
225
const fs = require('fs');
226
fs.writeFileSync('index.json', JSON.stringify(serialized));
227
228
// Load from storage
229
const storedData = JSON.parse(localStorage.getItem('searchIndex'));
230
const loadedIdx = lunr.Index.load(storedData);
231
232
// Load from file (Node.js)
233
const fileData = JSON.parse(fs.readFileSync('index.json', 'utf8'));
234
const fileIdx = lunr.Index.load(fileData);
235
236
// Use loaded index normally
237
const results = loadedIdx.search('searchable');
238
```
239
240
## Search Result Processing
241
242
### Result Structure
243
244
```javascript { .api }
245
/**
246
* Individual search result
247
* @typedef {Object} SearchResult
248
* @property {string} ref - Document reference identifier
249
* @property {number} score - Relevance score (0.0 to ~4.0+, higher = more relevant)
250
* @property {lunr.MatchData} matchData - Detailed match information (if available)
251
*/
252
253
/**
254
* Match data providing detailed information about matches
255
* @typedef {Object} MatchData
256
* @property {Object} metadata - Term metadata including positions and frequencies
257
*/
258
```
259
260
**Usage Examples:**
261
262
```javascript
263
const results = idx.search('javascript tutorial');
264
265
results.forEach(result => {
266
console.log(`Document: ${result.ref}`);
267
console.log(`Score: ${result.score.toFixed(3)}`);
268
269
if (result.matchData) {
270
// Access detailed match information
271
const metadata = result.matchData.metadata;
272
Object.keys(metadata).forEach(term => {
273
console.log(`Term "${term}" found in:`, Object.keys(metadata[term]));
274
});
275
}
276
});
277
```
278
279
### Result Ranking and Scoring
280
281
Understanding and working with Lunr's BM25-based scoring system.
282
283
```javascript
284
// Results are already sorted by score (highest first)
285
const results = idx.search('query terms');
286
287
// Custom result processing
288
const processedResults = results
289
.filter(result => result.score > 0.5) // Filter by minimum score
290
.slice(0, 10) // Limit to top 10
291
.map(result => ({
292
...result,
293
normalizedScore: Math.min(result.score / 2.0, 1.0) // Normalize score to 0-1
294
}));
295
296
// Group results by score ranges
297
const groupedResults = {
298
high: results.filter(r => r.score > 1.5),
299
medium: results.filter(r => r.score > 0.5 && r.score <= 1.5),
300
low: results.filter(r => r.score <= 0.5)
301
};
302
```
303
304
## Advanced Search Patterns
305
306
### Multi-field Weighted Search
307
308
```javascript
309
// Search across multiple fields with different weights
310
const results = idx.query(function (q) {
311
const searchTerm = 'javascript';
312
313
// High weight for title matches
314
q.term(searchTerm, {
315
fields: ['title'],
316
boost: 10
317
});
318
319
// Medium weight for content matches
320
q.term(searchTerm, {
321
fields: ['content'],
322
boost: 5
323
});
324
325
// Low weight for tag matches
326
q.term(searchTerm, {
327
fields: ['tags'],
328
boost: 2
329
});
330
});
331
```
332
333
### Search with Auto-complete
334
335
```javascript
336
// Implement auto-complete functionality
337
function autoComplete(partialTerm, maxResults = 5) {
338
return idx.query(function (q) {
339
// Add wildcard for prefix matching
340
q.term(partialTerm, {
341
wildcard: lunr.Query.wildcard.TRAILING,
342
boost: 10
343
});
344
345
// Also add fuzzy matching for typos
346
q.term(partialTerm, {
347
editDistance: 1,
348
boost: 5
349
});
350
}).slice(0, maxResults);
351
}
352
353
const suggestions = autoComplete('java'); // Finds "javascript", "java", etc.
354
```
355
356
### Faceted Search
357
358
```javascript
359
// Combine field restrictions for faceted search
360
function facetedSearch(query, facets = {}) {
361
return idx.query(function (q) {
362
// Main search term
363
if (query) {
364
q.term(query, { boost: 10 });
365
}
366
367
// Apply facet filters
368
Object.entries(facets).forEach(([field, value]) => {
369
q.term(value, {
370
fields: [field],
371
presence: lunr.Query.presence.REQUIRED
372
});
373
});
374
});
375
}
376
377
// Search for "tutorial" in documents tagged as "beginner" with category "javascript"
378
const facetedResults = facetedSearch('tutorial', {
379
tags: 'beginner',
380
category: 'javascript'
381
});
382
```