or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bloom-filters.mdclient-management.mdindex.mdjson-operations.mdredis-commands.mdsearch-indexing.mdtime-series.md

search-indexing.mddocs/

0

# Search and Indexing

1

2

Full-text search, indexing, and aggregation capabilities using RediSearch for complex query operations on Redis data. Provides powerful search features including full-text search, numeric filtering, geo-spatial queries, and advanced aggregation.

3

4

## Capabilities

5

6

### Index Management

7

8

Operations for creating, managing, and configuring search indexes.

9

10

```typescript { .api }

11

/**

12

* Create a search index with schema definition

13

* @param index - Name of the index

14

* @param schema - Index schema definition

15

* @param options - Optional index configuration

16

* @returns 'OK'

17

*/

18

function create(index: string, schema: RediSearchSchema, options?: FtCreateOptions): Promise<SimpleStringReply<'OK'>>;

19

20

/**

21

* Get information about a search index

22

* @param index - Name of the index

23

* @returns Array containing index information

24

*/

25

function info(index: string): Promise<ArrayReply>;

26

27

/**

28

* Drop a search index

29

* @param index - Name of the index

30

* @param options - Optional drop configuration

31

* @returns 'OK'

32

*/

33

function dropIndex(index: string, options?: FtDropIndexOptions): Promise<SimpleStringReply<'OK'>>;

34

35

/**

36

* Alter an existing index by adding new fields

37

* @param index - Name of the index

38

* @param schema - New fields to add to the schema

39

* @returns 'OK'

40

*/

41

function alter(index: string, schema: RediSearchSchema): Promise<SimpleStringReply<'OK'>>;

42

43

/**

44

* List all search indexes

45

* @returns Array of index names

46

*/

47

function _list(): Promise<ArrayReply<BlobStringReply>>;

48

49

interface RediSearchSchema {

50

[fieldName: string]: SchemaFieldDefinition;

51

}

52

53

interface SchemaFieldDefinition {

54

/** Field type */

55

type: SchemaFieldType;

56

/** Field is sortable */

57

SORTABLE?: boolean;

58

/** Field cannot be searched */

59

NOINDEX?: boolean;

60

/** Store original value for highlighting */

61

NOSTEM?: boolean;

62

/** Text field specific options */

63

WEIGHT?: number;

64

PHONETIC?: SchemaTextFieldPhonetic;

65

/** Numeric/geo field options */

66

SEPARATOR?: string;

67

/** Vector field options */

68

ALGORITHM?: SchemaVectorFieldAlgorithm;

69

DIM?: number;

70

DISTANCE_METRIC?: 'L2' | 'IP' | 'COSINE';

71

}

72

73

type SchemaFieldType = 'TEXT' | 'NUMERIC' | 'GEO' | 'TAG' | 'VECTOR';

74

type SchemaTextFieldPhonetic = 'dm:en' | 'dm:fr' | 'fm';

75

type SchemaVectorFieldAlgorithm = 'FLAT' | 'HNSW';

76

77

interface FtCreateOptions {

78

/** Key prefix for indexed documents */

79

PREFIX?: string | string[];

80

/** Custom key filter expression */

81

FILTER?: string;

82

/** Default language for text fields */

83

LANGUAGE?: RediSearchLanguage;

84

/** Default field for searches */

85

LANGUAGE_FIELD?: string;

86

/** Default score for documents */

87

SCORE?: number;

88

/** Field containing document score */

89

SCORE_FIELD?: string;

90

/** Field containing document payload */

91

PAYLOAD_FIELD?: string;

92

/** Maximum number of text records */

93

MAXTEXTFIELDS?: boolean;

94

/** Disable stemming */

95

NOSTEM?: boolean;

96

/** Disable stop words */

97

NOFREQS?: boolean;

98

/** Disable term offset vectors */

99

NOOFFSETS?: boolean;

100

/** Number of background indexing threads */

101

NOHL?: boolean;

102

/** Custom stop words */

103

STOPWORDS?: string[];

104

}

105

106

interface FtDropIndexOptions {

107

/** Also delete the documents */

108

DD?: boolean;

109

}

110

111

type RediSearchLanguage = 'arabic' | 'danish' | 'dutch' | 'english' | 'finnish' | 'french' | 'german' | 'hungarian' | 'italian' | 'norwegian' | 'portuguese' | 'romanian' | 'russian' | 'spanish' | 'swedish' | 'turkish' | 'chinese';

112

```

113

114

**Usage Examples:**

115

116

```typescript

117

import { createClient } from "redis";

118

119

const client = createClient();

120

await client.connect();

121

122

// Create a search index for products

123

await client.ft.create("products", {

124

name: { type: 'TEXT', SORTABLE: true },

125

description: { type: 'TEXT' },

126

price: { type: 'NUMERIC', SORTABLE: true },

127

category: { type: 'TAG', SORTABLE: true },

128

location: { type: 'GEO' },

129

tags: { type: 'TAG', SEPARATOR: ',' }

130

}, {

131

PREFIX: 'product:',

132

LANGUAGE: 'english'

133

});

134

135

// Get index information

136

const indexInfo = await client.ft.info("products");

137

console.log("Index info:", indexInfo);

138

139

// List all indexes

140

const indexes = await client.ft._list();

141

console.log("Available indexes:", indexes);

142

143

// Add new field to existing index

144

await client.ft.alter("products", {

145

brand: { type: 'TAG', SORTABLE: true }

146

});

147

148

// Drop index (keeping documents)

149

await client.ft.dropIndex("products");

150

151

// Drop index and delete documents

152

await client.ft.dropIndex("products", { DD: true });

153

```

154

155

### Search Operations

156

157

Core search functionality with query parsing and result formatting.

158

159

```typescript { .api }

160

/**

161

* Search the index with a query

162

* @param index - Name of the index

163

* @param query - Search query string

164

* @param options - Optional search parameters

165

* @returns Search results with documents and metadata

166

*/

167

function search(index: string, query: string, options?: FtSearchOptions): Promise<SearchReply>;

168

169

/**

170

* Search without returning document content

171

* @param index - Name of the index

172

* @param query - Search query string

173

* @param options - Optional search parameters

174

* @returns Search results with document IDs only

175

*/

176

function searchNoContent(index: string, query: string, options?: FtSearchOptions): Promise<SearchReply>;

177

178

/**

179

* Explain query execution plan

180

* @param index - Name of the index

181

* @param query - Search query string

182

* @param options - Optional query options

183

* @returns Query execution plan

184

*/

185

function explain(index: string, query: string, options?: FtExplainOptions): Promise<BlobStringReply>;

186

187

/**

188

* Profile search query performance

189

* @param index - Name of the index

190

* @param query - Search query string

191

* @param options - Optional search parameters

192

* @returns Profiling information with search results

193

*/

194

function profileSearch(index: string, query: string, options?: FtSearchOptions): Promise<ArrayReply>;

195

196

interface FtSearchOptions {

197

/** Return only document IDs */

198

NOCONTENT?: boolean;

199

/** Include term frequency information */

200

WITHSCORES?: boolean;

201

/** Include payload information */

202

WITHPAYLOADS?: boolean;

203

/** Sort by field */

204

SORTBY?: {

205

BY: string;

206

DIRECTION?: 'ASC' | 'DESC';

207

};

208

/** Limit results */

209

LIMIT?: {

210

from: number;

211

size: number;

212

};

213

/** Specific fields to return */

214

RETURN?: string[];

215

/** Highlight matching terms */

216

HIGHLIGHT?: {

217

FIELDS?: string[];

218

TAGS?: {

219

open: string;

220

close: string;

221

};

222

};

223

/** Summarize fields */

224

SUMMARIZE?: {

225

FIELDS?: string[];

226

FRAGS?: number;

227

LEN?: number;

228

SEPARATOR?: string;

229

};

230

/** Default language */

231

LANGUAGE?: RediSearchLanguage;

232

/** Expression filter */

233

FILTER?: string;

234

/** Geographic filter */

235

GEOFILTER?: {

236

field: string;

237

lon: number;

238

lat: number;

239

radius: number;

240

unit: 'm' | 'km' | 'mi' | 'ft';

241

};

242

/** Include term position information */

243

INKEYS?: string[];

244

/** Include tag values */

245

INFIELDS?: string[];

246

/** Return raw document values */

247

RETURN_RAW?: boolean;

248

/** Disable stemming */

249

NOSTEM?: boolean;

250

/** Custom scoring function */

251

SCORER?: string;

252

}

253

254

interface SearchReply {

255

/** Total number of results */

256

total: number;

257

/** Array of document results */

258

documents: SearchDocument[];

259

}

260

261

interface SearchDocument {

262

/** Document ID */

263

id: string;

264

/** Document score */

265

score?: number;

266

/** Document payload */

267

payload?: string;

268

/** Document fields */

269

value: Record<string, string>;

270

}

271

```

272

273

**Usage Examples:**

274

275

```typescript

276

// Add some sample data first

277

await client.hSet("product:1", {

278

name: "Smartphone",

279

description: "Latest Android smartphone with great camera",

280

price: "599",

281

category: "electronics",

282

tags: "mobile,android,camera"

283

});

284

285

await client.hSet("product:2", {

286

name: "Laptop",

287

description: "High-performance laptop for developers",

288

price: "1299",

289

category: "computers",

290

tags: "laptop,development,performance"

291

});

292

293

// Basic search

294

const results = await client.ft.search("products", "smartphone");

295

console.log(`Found ${results.total} results:`, results.documents);

296

297

// Search with options

298

const searchResults = await client.ft.search("products", "camera OR laptop", {

299

WITHSCORES: true,

300

SORTBY: { BY: "price", DIRECTION: "ASC" },

301

LIMIT: { from: 0, size: 10 },

302

HIGHLIGHT: {

303

FIELDS: ["name", "description"],

304

TAGS: { open: "<mark>", close: "</mark>" }

305

}

306

});

307

308

// Filtered search

309

const electronicsResults = await client.ft.search("products", "*", {

310

FILTER: "@category:{electronics}",

311

SORTBY: { BY: "price", DIRECTION: "DESC" }

312

});

313

314

// Price range search

315

const priceResults = await client.ft.search("products", "@price:[500 1000]");

316

317

// Geographic search (if location field exists)

318

const nearbyResults = await client.ft.search("products", "*", {

319

GEOFILTER: {

320

field: "location",

321

lon: -122.4194,

322

lat: 37.7749,

323

radius: 10,

324

unit: "km"

325

}

326

});

327

328

// Get search explanation

329

const explanation = await client.ft.explain("products", "smartphone camera");

330

console.log("Query plan:", explanation);

331

```

332

333

### Aggregation Operations

334

335

Advanced aggregation operations for complex data analysis and reporting.

336

337

```typescript { .api }

338

/**

339

* Perform aggregation query on search index

340

* @param index - Name of the index

341

* @param query - Search query string

342

* @param options - Aggregation pipeline steps

343

* @returns Aggregation results

344

*/

345

function aggregate(index: string, query: string, ...options: FtAggregateStep[]): Promise<ArrayReply>;

346

347

/**

348

* Perform aggregation with cursor for large result sets

349

* @param index - Name of the index

350

* @param query - Search query string

351

* @param options - Aggregation options with cursor configuration

352

* @returns Aggregation results with cursor

353

*/

354

function aggregateWithCursor(index: string, query: string, options?: FtAggregateWithCursorOptions): Promise<ArrayReply>;

355

356

/**

357

* Profile aggregation query performance

358

* @param index - Name of the index

359

* @param query - Search query string

360

* @param options - Aggregation pipeline steps

361

* @returns Profiling information with aggregation results

362

*/

363

function profileAggregate(index: string, query: string, ...options: FtAggregateStep[]): Promise<ArrayReply>;

364

365

type FtAggregateStep =

366

| { type: 'GROUPBY'; fields: string[]; reducers: FtAggregateGroupByReducer[] }

367

| { type: 'SORTBY'; fields: Array<{ field: string; direction?: 'ASC' | 'DESC' }> }

368

| { type: 'APPLY'; expression: string; as: string }

369

| { type: 'LIMIT'; offset: number; count: number }

370

| { type: 'FILTER'; expression: string };

371

372

type FtAggregateGroupByReducer =

373

| { type: 'COUNT'; as?: string }

374

| { type: 'COUNT_DISTINCT'; field: string; as?: string }

375

| { type: 'SUM'; field: string; as?: string }

376

| { type: 'MIN'; field: string; as?: string }

377

| { type: 'MAX'; field: string; as?: string }

378

| { type: 'AVG'; field: string; as?: string }

379

| { type: 'STDDEV'; field: string; as?: string }

380

| { type: 'TOLIST'; field: string; as?: string };

381

382

interface FtAggregateWithCursorOptions {

383

/** Cursor read size */

384

WITHCURSOR?: {

385

COUNT?: number;

386

MAXIDLE?: number;

387

};

388

/** Aggregation steps */

389

steps?: FtAggregateStep[];

390

}

391

```

392

393

**Usage Examples:**

394

395

```typescript

396

// Group by category and count

397

const categoryStats = await client.ft.aggregate("products", "*",

398

{

399

type: 'GROUPBY',

400

fields: ['@category'],

401

reducers: [

402

{ type: 'COUNT', as: 'count' },

403

{ type: 'AVG', field: '@price', as: 'avg_price' },

404

{ type: 'MIN', field: '@price', as: 'min_price' },

405

{ type: 'MAX', field: '@price', as: 'max_price' }

406

]

407

},

408

{

409

type: 'SORTBY',

410

fields: [{ field: '@count', direction: 'DESC' }]

411

}

412

);

413

414

// Price range analysis

415

const priceRanges = await client.ft.aggregate("products", "*",

416

{

417

type: 'APPLY',

418

expression: 'floor(@price/100)*100',

419

as: 'price_range'

420

},

421

{

422

type: 'GROUPBY',

423

fields: ['@price_range'],

424

reducers: [

425

{ type: 'COUNT', as: 'products_in_range' }

426

]

427

},

428

{

429

type: 'SORTBY',

430

fields: [{ field: '@price_range', direction: 'ASC' }]

431

}

432

);

433

434

// Complex aggregation with multiple steps

435

const complexAgg = await client.ft.aggregate("products", "electronics",

436

{

437

type: 'FILTER',

438

expression: '@price > 100'

439

},

440

{

441

type: 'APPLY',

442

expression: '@price * 0.1',

443

as: 'tax'

444

},

445

{

446

type: 'GROUPBY',

447

fields: ['@category'],

448

reducers: [

449

{ type: 'COUNT', as: 'count' },

450

{ type: 'SUM', field: '@price', as: 'total_price' },

451

{ type: 'SUM', field: '@tax', as: 'total_tax' }

452

]

453

},

454

{

455

type: 'LIMIT',

456

offset: 0,

457

count: 10

458

}

459

);

460

```

461

462

### Cursor Operations

463

464

Cursor-based operations for handling large result sets efficiently.

465

466

```typescript { .api }

467

/**

468

* Read from aggregation cursor

469

* @param index - Name of the index

470

* @param cursor - Cursor ID

471

* @param options - Read options

472

* @returns Next batch of results

473

*/

474

function cursorRead(index: string, cursor: number, options?: FtCursorReadOptions): Promise<ArrayReply>;

475

476

/**

477

* Delete aggregation cursor

478

* @param index - Name of the index

479

* @param cursor - Cursor ID

480

* @returns 'OK'

481

*/

482

function cursorDel(index: string, cursor: number): Promise<SimpleStringReply<'OK'>>;

483

484

interface FtCursorReadOptions {

485

/** Number of results to read */

486

COUNT?: number;

487

}

488

```

489

490

**Usage Examples:**

491

492

```typescript

493

// Create aggregation with cursor

494

const cursorResult = await client.ft.aggregateWithCursor("products", "*", {

495

WITHCURSOR: { COUNT: 100, MAXIDLE: 300000 },

496

steps: [

497

{

498

type: 'GROUPBY',

499

fields: ['@category'],

500

reducers: [{ type: 'COUNT', as: 'count' }]

501

}

502

]

503

});

504

505

// Extract cursor ID from result

506

const cursorId = cursorResult[cursorResult.length - 1];

507

508

// Read more results

509

const moreResults = await client.ft.cursorRead("products", cursorId, { COUNT: 50 });

510

511

// Clean up cursor

512

await client.ft.cursorDel("products", cursorId);

513

```

514

515

### Suggestion Operations

516

517

Auto-complete and suggestion functionality.

518

519

```typescript { .api }

520

/**

521

* Add suggestion to auto-complete dictionary

522

* @param key - Dictionary key

523

* @param string - Suggestion string

524

* @param score - Suggestion score

525

* @param options - Optional payload and increment behavior

526

* @returns Number of suggestions added

527

*/

528

function sugAdd(key: string, string: string, score: number, options?: FtSugAddOptions): Promise<NumberReply>;

529

530

/**

531

* Get suggestions from auto-complete dictionary

532

* @param key - Dictionary key

533

* @param prefix - Prefix to match

534

* @param options - Optional parameters for fuzzy matching and limits

535

* @returns Array of matching suggestions

536

*/

537

function sugGet(key: string, prefix: string, options?: FtSugGetOptions): Promise<ArrayReply<BlobStringReply>>;

538

539

/**

540

* Get suggestions with scores

541

* @param key - Dictionary key

542

* @param prefix - Prefix to match

543

* @param options - Optional parameters

544

* @returns Array of suggestions with scores

545

*/

546

function sugGetWithScores(key: string, prefix: string, options?: FtSugGetOptions): Promise<ArrayReply>;

547

548

/**

549

* Delete suggestion from dictionary

550

* @param key - Dictionary key

551

* @param string - Suggestion string to delete

552

* @returns 1 if deleted, 0 if not found

553

*/

554

function sugDel(key: string, string: string): Promise<BooleanReply>;

555

556

/**

557

* Get number of suggestions in dictionary

558

* @param key - Dictionary key

559

* @returns Number of suggestions

560

*/

561

function sugLen(key: string): Promise<NumberReply>;

562

563

interface FtSugAddOptions {

564

/** Increment score if suggestion exists */

565

INCR?: boolean;

566

/** Optional payload data */

567

PAYLOAD?: string;

568

}

569

570

interface FtSugGetOptions {

571

/** Enable fuzzy matching */

572

FUZZY?: boolean;

573

/** Maximum number of results */

574

MAX?: number;

575

/** Include scores in results */

576

WITHSCORES?: boolean;

577

/** Include payloads in results */

578

WITHPAYLOADS?: boolean;

579

}

580

```

581

582

**Usage Examples:**

583

584

```typescript

585

// Add suggestions to auto-complete

586

await client.ft.sugAdd("product_suggestions", "smartphone", 1.0);

587

await client.ft.sugAdd("product_suggestions", "smart tv", 0.8);

588

await client.ft.sugAdd("product_suggestions", "smart watch", 0.9, { PAYLOAD: "category:wearable" });

589

590

// Get suggestions

591

const suggestions = await client.ft.sugGet("product_suggestions", "smart", { MAX: 5 });

592

// ["smartphone", "smart watch", "smart tv"]

593

594

// Get suggestions with scores

595

const withScores = await client.ft.sugGetWithScores("product_suggestions", "smart", { MAX: 3 });

596

// ["smartphone", "1", "smart watch", "0.9", "smart tv", "0.8"]

597

598

// Fuzzy matching

599

const fuzzy = await client.ft.sugGet("product_suggestions", "smar", { FUZZY: true, MAX: 3 });

600

601

// Get suggestion count

602

const count = await client.ft.sugLen("product_suggestions"); // 3

603

604

// Delete suggestion

605

await client.ft.sugDel("product_suggestions", "smart tv");

606

```

607

608

### Dictionary and Synonym Management

609

610

Operations for managing dictionaries and synonyms.

611

612

```typescript { .api }

613

/**

614

* Add terms to dictionary

615

* @param dictionary - Dictionary name

616

* @param terms - Terms to add

617

* @returns Number of new terms added

618

*/

619

function dictAdd(dictionary: string, ...terms: string[]): Promise<NumberReply>;

620

621

/**

622

* Delete terms from dictionary

623

* @param dictionary - Dictionary name

624

* @param terms - Terms to delete

625

* @returns Number of terms deleted

626

*/

627

function dictDel(dictionary: string, ...terms: string[]): Promise<NumberReply>;

628

629

/**

630

* Dump all terms in dictionary

631

* @param dictionary - Dictionary name

632

* @returns Array of all terms in dictionary

633

*/

634

function dictDump(dictionary: string): Promise<ArrayReply<BlobStringReply>>;

635

636

/**

637

* Update synonym group

638

* @param index - Index name

639

* @param groupId - Synonym group ID

640

* @param terms - Terms in the synonym group

641

* @param options - Optional skip initial scan

642

* @returns 'OK'

643

*/

644

function synUpdate(index: string, groupId: string, terms: string[], options?: { SKIPINITIALSCAN?: boolean }): Promise<SimpleStringReply<'OK'>>;

645

646

/**

647

* Dump synonym groups

648

* @param index - Index name

649

* @returns Array of synonym group information

650

*/

651

function synDump(index: string): Promise<ArrayReply>;

652

```

653

654

**Usage Examples:**

655

656

```typescript

657

// Dictionary management

658

await client.ft.dictAdd("stopwords", "the", "a", "an", "and", "or", "but");

659

const stopwordCount = await client.ft.dictAdd("stopwords", "in", "on", "at"); // Returns count of new words

660

661

// View dictionary contents

662

const allStopwords = await client.ft.dictDump("stopwords");

663

664

// Remove words from dictionary

665

await client.ft.dictDel("stopwords", "but", "or");

666

667

// Synonym management

668

await client.ft.synUpdate("products", "smartphones", [

669

"smartphone", "mobile phone", "cell phone", "mobile device"

670

]);

671

672

await client.ft.synUpdate("products", "laptops", [

673

"laptop", "notebook", "portable computer"

674

]);

675

676

// View synonyms

677

const synonyms = await client.ft.synDump("products");

678

```

679

680

### Alias Management

681

682

Index alias operations for flexible index management.

683

684

```typescript { .api }

685

/**

686

* Add alias for an index

687

* @param alias - Alias name

688

* @param index - Target index name

689

* @returns 'OK'

690

*/

691

function aliasAdd(alias: string, index: string): Promise<SimpleStringReply<'OK'>>;

692

693

/**

694

* Delete an alias

695

* @param alias - Alias name to delete

696

* @returns 'OK'

697

*/

698

function aliasDel(alias: string): Promise<SimpleStringReply<'OK'>>;

699

700

/**

701

* Update alias to point to different index

702

* @param alias - Alias name

703

* @param index - New target index name

704

* @returns 'OK'

705

*/

706

function aliasUpdate(alias: string, index: string): Promise<SimpleStringReply<'OK'>>;

707

```

708

709

**Usage Examples:**

710

711

```typescript

712

// Create alias for current index

713

await client.ft.aliasAdd("current_products", "products_v1");

714

715

// Use alias in searches (same as using index name)

716

const results = await client.ft.search("current_products", "smartphone");

717

718

// Update alias to point to new index version

719

await client.ft.aliasUpdate("current_products", "products_v2");

720

721

// Delete alias when no longer needed

722

await client.ft.aliasDel("current_products");

723

```

724

725

## Search Query Syntax

726

727

RediSearch supports powerful query syntax for complex searches:

728

729

```typescript

730

// Query syntax examples:

731

"hello world" // Full-text search for both terms

732

"hello | world" // OR search

733

"hello -world" // Exclude term

734

"\"hello world\"" // Exact phrase

735

"hello*" // Prefix search

736

"%hello%" // Fuzzy search

737

"@title:hello" // Field-specific search

738

"@price:[100 200]" // Numeric range

739

"@location:[lat lon radius unit]" // Geographic filter

740

"@tags:{electronics|computers}" // Tag filter

741

"(@title:hello) (@price:[100 200])" // Complex query

742

```

743

744

## Constants and Enums

745

746

```typescript { .api }

747

const REDISEARCH_LANGUAGE = {

748

ARABIC: 'arabic',

749

DANISH: 'danish',

750

DUTCH: 'dutch',

751

ENGLISH: 'english',

752

FINNISH: 'finnish',

753

FRENCH: 'french',

754

GERMAN: 'german',

755

HUNGARIAN: 'hungarian',

756

ITALIAN: 'italian',

757

NORWEGIAN: 'norwegian',

758

PORTUGUESE: 'portuguese',

759

ROMANIAN: 'romanian',

760

RUSSIAN: 'russian',

761

SPANISH: 'spanish',

762

SWEDISH: 'swedish',

763

TURKISH: 'turkish',

764

CHINESE: 'chinese'

765

} as const;

766

767

const SCHEMA_FIELD_TYPE = {

768

TEXT: 'TEXT',

769

NUMERIC: 'NUMERIC',

770

GEO: 'GEO',

771

TAG: 'TAG',

772

VECTOR: 'VECTOR'

773

} as const;

774

775

const FT_AGGREGATE_GROUP_BY_REDUCERS = {

776

COUNT: 'COUNT',

777

COUNT_DISTINCT: 'COUNT_DISTINCT',

778

SUM: 'SUM',

779

MIN: 'MIN',

780

MAX: 'MAX',

781

AVG: 'AVG',

782

STDDEV: 'STDDEV',

783

TOLIST: 'TOLIST'

784

} as const;

785

```