-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Do not merge] : [@azure/cosmos] Add Full text search support for cosmos-explorer #31710
base: main
Are you sure you want to change the base?
Changes from 33 commits
360d332
8dc5356
46bd786
3e36c96
e799caf
1c4870c
f7d80ca
2a7f44d
dcbd5a4
6332df2
2d64ca9
aaf45f4
636e745
96647b5
b859b13
d4799a6
16c4ca4
26d0929
9c8cd6d
6a00339
3349ef2
82b2974
f348d4d
00f5aef
7ae8287
fa097e0
af72225
e46c167
28901d1
6457b0e
bd40fe2
c38f6d6
a9fc970
02f24b8
fa230a2
4bb6efa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -593,6 +593,7 @@ export const Constants: { | |
MinimumInclusiveEffectivePartitionKey: string; | ||
MaximumExclusiveEffectivePartitionKey: string; | ||
}; | ||
NonStreamingQueryDefaultRUThreshold: number; | ||
AllVersionsAndDeletesChangeFeedWireFormatVersion: string; | ||
ChangeFeedIfNoneMatchStartFromNowHeader: string; | ||
}; | ||
|
@@ -634,6 +635,7 @@ export interface ContainerDefinition { | |
computedProperties?: ComputedProperty[]; | ||
conflictResolutionPolicy?: ConflictResolutionPolicy; | ||
defaultTtl?: number; | ||
fullTextPolicy?: FullTextPolicy; | ||
geospatialConfig?: { | ||
type: GeospatialType; | ||
}; | ||
|
@@ -1095,6 +1097,23 @@ export class FeedResponse<TResource> { | |
readonly resources: TResource[]; | ||
} | ||
|
||
// @public | ||
export interface FullTextIndex { | ||
path: string; | ||
} | ||
|
||
// @public | ||
export interface FullTextPath { | ||
language: string; | ||
path: string; | ||
} | ||
|
||
// @public | ||
export interface FullTextPolicy { | ||
defaultLanguage: string; | ||
fullTextPaths: FullTextPath[]; | ||
} | ||
|
||
// @public (undocumented) | ||
export type GatewayStatistics = { | ||
activityId?: string; | ||
|
@@ -1161,6 +1180,15 @@ export enum HTTPMethod { | |
put = "PUT" | ||
} | ||
|
||
// @public | ||
export interface HybridSearchQueryInfo { | ||
componentQueryInfos: QueryInfo[]; | ||
globalStatisticsQuery: string; | ||
requiresGlobalStatistics: boolean; | ||
skip: number; | ||
take: number; | ||
} | ||
|
||
// @public (undocumented) | ||
export interface Index { | ||
// (undocumented) | ||
|
@@ -1192,6 +1220,7 @@ export interface IndexingPolicy { | |
automatic?: boolean; | ||
compositeIndexes?: CompositePath[][]; | ||
excludedPaths?: IndexedPath[]; | ||
fullTextIndexes?: FullTextIndex[]; | ||
includedPaths?: IndexedPath[]; | ||
indexingMode?: keyof typeof IndexingMode; | ||
// (undocumented) | ||
|
@@ -1452,10 +1481,11 @@ export type OperationWithItem = OperationBase & { | |
|
||
// @public (undocumented) | ||
export interface PartitionedQueryExecutionInfo { | ||
hybridSearchQueryInfo?: HybridSearchQueryInfo; | ||
// (undocumented) | ||
partitionedQueryExecutionInfoVersion: number; | ||
// (undocumented) | ||
queryInfo: QueryInfo; | ||
queryInfo?: QueryInfo; | ||
// (undocumented) | ||
queryRanges: QueryRange[]; | ||
} | ||
|
@@ -1671,11 +1701,11 @@ export interface QueryInfo { | |
export class QueryIterator<T> { | ||
// Warning: (ae-forgotten-export) The symbol "FetchFunctionCallback" needs to be exported by the entry point index.d.ts | ||
constructor(clientContext: ClientContext, query: SqlQuerySpec | string, options: FeedOptions, fetchFunctions: FetchFunctionCallback | FetchFunctionCallback[], resourceLink?: string, resourceType?: ResourceType); | ||
fetchAll(): Promise<FeedResponse<T>>; | ||
fetchAll(options?: QueryOperationOptions): Promise<FeedResponse<T>>; | ||
// (undocumented) | ||
fetchAllInternal(diagnosticNode: DiagnosticNodeInternal): Promise<FeedResponse<T>>; | ||
fetchNext(): Promise<FeedResponse<T>>; | ||
getAsyncIterator(): AsyncIterable<FeedResponse<T>>; | ||
fetchAllInternal(diagnosticNode: DiagnosticNodeInternal, options?: QueryOperationOptions): Promise<FeedResponse<T>>; | ||
fetchNext(options?: QueryOperationOptions): Promise<FeedResponse<T>>; | ||
getAsyncIterator(options?: QueryOperationOptions): AsyncIterable<FeedResponse<T>>; | ||
hasMoreResults(): boolean; | ||
reset(): void; | ||
} | ||
|
@@ -1764,6 +1794,11 @@ export const QueryMetricsConstants: { | |
SchedulingMetricsText: string; | ||
}; | ||
|
||
// @public (undocumented) | ||
export interface QueryOperationOptions { | ||
ruCapPerOperation?: number; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a well known concept for request units in the case of Cosmos DB https://learn.microsoft.com/en-us/azure/cosmos-db/request-units |
||
} | ||
|
||
// @public (undocumented) | ||
export class QueryPreparationTimes { | ||
constructor(queryCompilationTime: TimeSpan, logicalPlanBuildTime: TimeSpan, physicalPlanBuildTime: TimeSpan, queryOptimizationTime: TimeSpan); | ||
|
@@ -2004,6 +2039,15 @@ export interface RetryOptions { | |
maxWaitTimeInSeconds: number; | ||
} | ||
|
||
// @public (undocumented) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed a bunch of shipped and new undocumented code - is that expected? |
||
export class RUCapPerOperationExceededError extends ErrorResponse { | ||
constructor(message?: string, fetchedResults?: any[]); | ||
// (undocumented) | ||
readonly code: string; | ||
// (undocumented) | ||
fetchedResults: any[]; | ||
} | ||
|
||
// @public (undocumented) | ||
export class RuntimeExecutionTimes { | ||
constructor(queryEngineExecutionTime: TimeSpan, systemFunctionExecutionTime: TimeSpan, userDefinedFunctionExecutionTime: TimeSpan); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
import semaphore from "semaphore"; | ||
|
||
/** | ||
* @hidden | ||
* @hidden | ||
* Specifies Net RUConsumed | ||
*/ | ||
export class RUConsumedManager { | ||
private ruConsumed: number = 0; | ||
private semaphore: any; | ||
|
||
constructor() { | ||
this.semaphore = semaphore(1); | ||
} | ||
|
||
getRUConsumed(): Promise<number> { | ||
return new Promise((resolve) => { | ||
this.semaphore.take(() => { | ||
this.semaphore.leave(); | ||
resolve(this.ruConsumed); | ||
}); | ||
}); | ||
} | ||
|
||
addToRUConsumed(value: number): Promise<void> { | ||
return new Promise((resolve) => { | ||
this.semaphore.take(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is a semaphore needed for synchronous operations? I thought JavaScript has run-to-completion semantics but maybe I missed something? |
||
this.ruConsumed += value; | ||
this.semaphore.leave(); | ||
resolve(); | ||
}); | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
/** | ||
* Represents a full text policy for a collection in the Azure Cosmos DB service. | ||
*/ | ||
export interface FullTextPolicy { | ||
/** | ||
* The default language for the full text . | ||
*/ | ||
defaultLanguage: string; | ||
/** | ||
* The paths to be indexed for full text search. | ||
*/ | ||
fullTextPaths: FullTextPath[]; | ||
} | ||
|
||
/** | ||
* Represents a full text path to be indexed in the Azure Cosmos DB service. | ||
*/ | ||
export interface FullTextPath { | ||
/** | ||
* The path to be indexed for full text search. | ||
*/ | ||
path: string; | ||
/** | ||
* The language for the full text path. | ||
*/ | ||
language: string; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
import { GlobalStatistics } from "../../request/globalStatistics"; | ||
import { Aggregator } from "./Aggregator"; | ||
|
||
export class GlobalStatisticsAggregator implements Aggregator { | ||
private globalStatistics: GlobalStatistics; | ||
|
||
constructor() { | ||
this.globalStatistics = { | ||
documentCount: 0, | ||
fullTextStatistics: [], | ||
}; | ||
} | ||
|
||
public aggregate(other: GlobalStatistics): void { | ||
if (!other) { | ||
return; | ||
} | ||
// Aggregate document count | ||
this.globalStatistics.documentCount += other.documentCount; | ||
// Ensure `fullTextStatistics` is initialized | ||
if (!other.fullTextStatistics || other.fullTextStatistics.length === 0) { | ||
return; | ||
} | ||
|
||
// Initialize `this.globalStatistics.fullTextStatistics` if it's empty | ||
if (this.globalStatistics.fullTextStatistics.length === 0) { | ||
this.globalStatistics.fullTextStatistics = other.fullTextStatistics.map((stat) => ({ | ||
totalWordCount: stat.totalWordCount, | ||
hitCounts: [...stat.hitCounts], | ||
})); | ||
} else { | ||
// Loop through `other.fullTextStatistics` to add values to `this.globalStatistics.fullTextStatistics` | ||
for (let i = 0; i < other.fullTextStatistics.length; i++) { | ||
const otherStat = other.fullTextStatistics[i]; | ||
|
||
// Ensure the index `i` is initialized | ||
if (!this.globalStatistics.fullTextStatistics[i]) { | ||
this.globalStatistics.fullTextStatistics[i] = { | ||
totalWordCount: 0, | ||
hitCounts: [], | ||
}; | ||
} | ||
|
||
// Add totalWordCount | ||
this.globalStatistics.fullTextStatistics[i].totalWordCount += otherStat.totalWordCount; | ||
|
||
// Aggregate `hitCounts` | ||
for (let j = 0; j < otherStat.hitCounts.length; j++) { | ||
// Initialize hit count if necessary | ||
if (this.globalStatistics.fullTextStatistics[i].hitCounts.length <= j) { | ||
this.globalStatistics.fullTextStatistics[i].hitCounts.push(0); | ||
} | ||
this.globalStatistics.fullTextStatistics[i].hitCounts[j] += otherStat.hitCounts[j]; | ||
} | ||
} | ||
} | ||
} | ||
|
||
public getResult(): GlobalStatistics { | ||
return this.globalStatistics; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FullTextSearchIndex, FullTextSearchPath, FullTextSearchPolicy might be clearer, just
fullText
doesn't tell me much