Skip to content

Make improvments to hybrid ux #246

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

Merged
merged 8 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ env:
WEAVIATE_124: 1.24.26
WEAVIATE_125: 1.25.28
WEAVIATE_126: 1.26.13
WEAVIATE_127: 1.27.8
WEAVIATE_128: 1.28.1-77a2178
WEAVIATE_127: 1.27.9
WEAVIATE_128: 1.28.2

jobs:
checks:
Expand Down
165 changes: 118 additions & 47 deletions src/collections/aggregate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,50 @@ import { FilterValue } from '../filters/index.js';

import { WeaviateQueryError } from '../../errors.js';
import { Aggregator } from '../../graphql/index.js';
import { toBase64FromMedia } from '../../index.js';
import { PrimitiveKeys, toBase64FromMedia } from '../../index.js';
import { Bm25QueryProperty } from '../query/types.js';
import { Serialize } from '../serialize/index.js';

export type AggregateBaseOptions<T, M> = {
export type AggregateBaseOptions<M> = {
filters?: FilterValue;
returnMetrics?: M;
};

export type AggregateGroupByOptions<T, M> = AggregateOptions<T, M> & {
groupBy: (keyof T & string) | GroupByAggregate<T>;
export type PropertyOf<T> = T extends undefined ? string : keyof T & string;

export type AggregateGroupByOptions<T, M> = AggregateBaseOptions<M> & {
groupBy: PropertyOf<T> | GroupByAggregate<T>;
};

export type GroupByAggregate<T> = {
property: keyof T & string;
property: PropertyOf<T>;
limit?: number;
};

export type AggregateOptions<T, M> = AggregateBaseOptions<T, M>;

export type AggregateBaseOverAllOptions<T, M> = AggregateBaseOptions<T, M>;
export type AggregateOverAllOptions<M> = AggregateBaseOptions<M>;

export type AggregateNearOptions<T, M> = AggregateBaseOptions<T, M> & {
export type AggregateNearOptions<M> = AggregateBaseOptions<M> & {
certainty?: number;
distance?: number;
objectLimit?: number;
targetVector?: string;
};

export type AggregateGroupByNearOptions<T, M> = AggregateNearOptions<T, M> & {
groupBy: (keyof T & string) | GroupByAggregate<T>;
export type AggregateHybridOptions<T, M> = AggregateBaseOptions<M> & {
alpha?: number;
maxVectorDistance?: number;
objectLimit?: number;
queryProperties?: (PrimitiveKeys<T> | Bm25QueryProperty<T>)[];
targetVector?: string;
vector?: number[];
};

export type AggregateGroupByHybridOptions<T, M> = AggregateHybridOptions<T, M> & {
groupBy: PropertyOf<T> | GroupByAggregate<T>;
};

export type AggregateGroupByNearOptions<T, M> = AggregateNearOptions<M> & {
groupBy: PropertyOf<T> | GroupByAggregate<T>;
};

export type AggregateBoolean = {
Expand Down Expand Up @@ -126,11 +140,11 @@ export type AggregateMetrics<M> = {
[K in keyof M]: M[K] extends true ? number : never;
};

export type MetricsProperty<T> = T extends undefined ? string : keyof T & string;
export type MetricsProperty<T> = PropertyOf<T>;

export const metrics = <T>() => {
return {
aggregate: <P extends MetricsProperty<T>>(property: P) => new MetricsManager<T, P>(property),
aggregate: <P extends PropertyOf<T>>(property: P) => new MetricsManager<T, P>(property),
};
};

Expand All @@ -143,10 +157,10 @@ export interface Metrics<T> {

See [the docs](https://weaviate.io/developers/weaviate/search/aggregate) for more details!
*/
aggregate: <P extends MetricsProperty<T>>(property: P) => MetricsManager<T, P>;
aggregate: <P extends PropertyOf<T>>(property: P) => MetricsManager<T, P>;
}

export class MetricsManager<T, P extends MetricsProperty<T>> {
export class MetricsManager<T, P extends PropertyOf<T>> {
private propertyName: P;

constructor(property: P) {
Expand Down Expand Up @@ -346,9 +360,26 @@ class AggregateManager<T> implements Aggregate<T> {
this.tenant = tenant;

this.groupBy = {
hybrid: <M extends PropertiesMetrics<T> | undefined = undefined>(
query: string,
opts: AggregateGroupByHybridOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]> => {
let builder = this.base(opts?.returnMetrics, opts?.filters, opts?.groupBy).withHybrid({
query: query,
alpha: opts?.alpha,
maxVectorDistance: opts?.maxVectorDistance,
properties: opts?.queryProperties as string[],
targetVectors: opts?.targetVector ? [opts.targetVector] : undefined,
vector: opts?.vector,
});
if (opts?.objectLimit) {
builder = builder.withObjectLimit(opts.objectLimit);
}
return this.doGroupBy(builder);
},
nearImage: async <M extends PropertiesMetrics<T> | undefined = undefined>(
image: string | Buffer,
opts?: AggregateGroupByNearOptions<T, M>
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]> => {
const builder = this.base(opts?.returnMetrics, opts?.filters, opts?.groupBy).withNearImage({
image: await toBase64FromMedia(image),
Expand All @@ -363,7 +394,7 @@ class AggregateManager<T> implements Aggregate<T> {
},
nearObject: <M extends PropertiesMetrics<T> | undefined = undefined>(
id: string,
opts?: AggregateGroupByNearOptions<T, M>
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]> => {
const builder = this.base(opts?.returnMetrics, opts?.filters, opts?.groupBy).withNearObject({
id: id,
Expand All @@ -378,7 +409,7 @@ class AggregateManager<T> implements Aggregate<T> {
},
nearText: <M extends PropertiesMetrics<T> | undefined = undefined>(
query: string | string[],
opts?: AggregateGroupByNearOptions<T, M>
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]> => {
const builder = this.base(opts?.returnMetrics, opts?.filters, opts?.groupBy).withNearText({
concepts: Array.isArray(query) ? query : [query],
Expand All @@ -393,7 +424,7 @@ class AggregateManager<T> implements Aggregate<T> {
},
nearVector: <M extends PropertiesMetrics<T> | undefined = undefined>(
vector: number[],
opts?: AggregateGroupByNearOptions<T, M>
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]> => {
const builder = this.base(opts?.returnMetrics, opts?.filters, opts?.groupBy).withNearVector({
vector: vector,
Expand All @@ -419,11 +450,7 @@ class AggregateManager<T> implements Aggregate<T> {
return new Aggregator(this.connection);
}

base(
metrics?: PropertiesMetrics<T>,
filters?: FilterValue,
groupBy?: (keyof T & string) | GroupByAggregate<T>
) {
base(metrics?: PropertiesMetrics<T>, filters?: FilterValue, groupBy?: PropertyOf<T> | GroupByAggregate<T>) {
let fields = 'meta { count }';
let builder = this.query().withClassName(this.name);
if (metrics) {
Expand Down Expand Up @@ -489,9 +516,27 @@ class AggregateManager<T> implements Aggregate<T> {
return new AggregateManager<T>(connection, name, dbVersionSupport, consistencyLevel, tenant);
}

hybrid<M extends PropertiesMetrics<T>>(
query: string,
opts?: AggregateHybridOptions<T, M>
): Promise<AggregateResult<T, M>> {
let builder = this.base(opts?.returnMetrics, opts?.filters).withHybrid({
query: query,
alpha: opts?.alpha,
maxVectorDistance: opts?.maxVectorDistance,
properties: opts?.queryProperties as string[],
targetVectors: opts?.targetVector ? [opts.targetVector] : undefined,
vector: opts?.vector,
});
if (opts?.objectLimit) {
builder = builder.withObjectLimit(opts.objectLimit);
}
return this.do(builder);
}

async nearImage<M extends PropertiesMetrics<T>>(
image: string | Buffer,
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>> {
const builder = this.base(opts?.returnMetrics, opts?.filters).withNearImage({
image: await toBase64FromMedia(image),
Expand All @@ -507,7 +552,7 @@ class AggregateManager<T> implements Aggregate<T> {

nearObject<M extends PropertiesMetrics<T>>(
id: string,
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>> {
const builder = this.base(opts?.returnMetrics, opts?.filters).withNearObject({
id: id,
Expand All @@ -523,7 +568,7 @@ class AggregateManager<T> implements Aggregate<T> {

nearText<M extends PropertiesMetrics<T>>(
query: string | string[],
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>> {
const builder = this.base(opts?.returnMetrics, opts?.filters).withNearText({
concepts: Array.isArray(query) ? query : [query],
Expand All @@ -539,7 +584,7 @@ class AggregateManager<T> implements Aggregate<T> {

nearVector<M extends PropertiesMetrics<T>>(
vector: number[],
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>> {
const builder = this.base(opts?.returnMetrics, opts?.filters).withNearVector({
vector: vector,
Expand All @@ -553,7 +598,7 @@ class AggregateManager<T> implements Aggregate<T> {
return this.do(builder);
}

overAll<M extends PropertiesMetrics<T>>(opts?: AggregateOptions<T, M>): Promise<AggregateResult<T, M>> {
overAll<M extends PropertiesMetrics<T>>(opts?: AggregateOverAllOptions<M>): Promise<AggregateResult<T, M>> {
const builder = this.base(opts?.returnMetrics, opts?.filters);
return this.do(builder);
}
Expand Down Expand Up @@ -588,7 +633,7 @@ class AggregateManager<T> implements Aggregate<T> {
prop: groupedBy.path[0],
value: groupedBy.value,
},
properties: rest.length > 0 ? rest : undefined,
properties: rest,
totalCount: meta?.count,
};
})
Expand All @@ -602,6 +647,19 @@ class AggregateManager<T> implements Aggregate<T> {
export interface Aggregate<T> {
/** This namespace contains methods perform a group by search while aggregating metrics. */
groupBy: AggregateGroupBy<T>;
/**
* Aggregate metrics over the objects returned by a hybrid search on this collection.
*
* This method requires that the objects in the collection have associated vectors.
*
* @param {string} query The text query to search for.
* @param {AggregateHybridOptions<T, M>} opts The options for the request.
* @returns {Promise<AggregateResult<T, M>[]>} The aggregated metrics for the objects returned by the vector search.
*/
hybrid<M extends PropertiesMetrics<T>>(
query: string,
opts?: AggregateHybridOptions<T, M>
): Promise<AggregateResult<T, M>>;
/**
* Aggregate metrics over the objects returned by a near image vector search on this collection.
*
Expand All @@ -615,7 +673,7 @@ export interface Aggregate<T> {
*/
nearImage<M extends PropertiesMetrics<T>>(
image: string | Buffer,
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>>;
/**
* Aggregate metrics over the objects returned by a near object search on this collection.
Expand All @@ -630,7 +688,7 @@ export interface Aggregate<T> {
*/
nearObject<M extends PropertiesMetrics<T>>(
id: string,
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>>;
/**
* Aggregate metrics over the objects returned by a near vector search on this collection.
Expand All @@ -645,7 +703,7 @@ export interface Aggregate<T> {
*/
nearText<M extends PropertiesMetrics<T>>(
query: string | string[],
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>>;
/**
* Aggregate metrics over the objects returned by a near vector search on this collection.
Expand All @@ -660,80 +718,93 @@ export interface Aggregate<T> {
*/
nearVector<M extends PropertiesMetrics<T>>(
vector: number[],
opts?: AggregateNearOptions<T, M>
opts?: AggregateNearOptions<M>
): Promise<AggregateResult<T, M>>;
/**
* Aggregate metrics over all the objects in this collection without any vector search.
*
* @param {AggregateOptions<T, M>} [opts] The options for the request.
* @returns {Promise<AggregateResult<T, M>[]>} The aggregated metrics for the objects in the collection.
*/
overAll<M extends PropertiesMetrics<T>>(opts?: AggregateOptions<T, M>): Promise<AggregateResult<T, M>>;
overAll<M extends PropertiesMetrics<T>>(opts?: AggregateOverAllOptions<M>): Promise<AggregateResult<T, M>>;
}

export interface AggregateGroupBy<T> {
/**
* Aggregate metrics over the objects returned by a near image vector search on this collection.
* Aggregate metrics over the objects grouped by a specified property and returned by a hybrid search on this collection.
*
* This method requires that the objects in the collection have associated vectors.
*
* @param {string} query The text query to search for.
* @param {AggregateGroupByHybridOptions<T, M>} opts The options for the request.
* @returns {Promise<AggregateGroupByResult<T, M>[]>} The aggregated metrics for the objects returned by the vector search.
*/
hybrid<M extends PropertiesMetrics<T>>(
query: string,
opts: AggregateGroupByHybridOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]>;
/**
* Aggregate metrics over the objects grouped by a specified property and returned by a near image vector search on this collection.
*
* At least one of `certainty`, `distance`, or `object_limit` must be specified here for the vector search.
*
* This method requires a vectorizer capable of handling base64-encoded images, e.g. `img2vec-neural`, `multi2vec-clip`, and `multi2vec-bind`.
*
* @param {string | Buffer} image The image to search on. This can be a base64 string, a file path string, or a buffer.
* @param {AggregateGroupByNearOptions<T, M>} [opts] The options for the request.
* @param {AggregateGroupByNearOptions<T, M>} opts The options for the request.
* @returns {Promise<AggregateGroupByResult<T, M>[]>} The aggregated metrics for the objects returned by the vector search.
*/
nearImage<M extends PropertiesMetrics<T>>(
image: string | Buffer,
opts?: AggregateGroupByNearOptions<T, M>
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]>;
/**
* Aggregate metrics over the objects returned by a near object search on this collection.
* Aggregate metrics over the objects grouped by a specified property and returned by a near object search on this collection.
*
* At least one of `certainty`, `distance`, or `object_limit` must be specified here for the vector search.
*
* This method requires that the objects in the collection have associated vectors.
*
* @param {string} id The ID of the object to search for.
* @param {AggregateGroupByNearOptions<T, M>} [opts] The options for the request.
* @param {AggregateGroupByNearOptions<T, M>} opts The options for the request.
* @returns {Promise<AggregateGroupByResult<T, M>[]>} The aggregated metrics for the objects returned by the vector search.
*/
nearObject<M extends PropertiesMetrics<T>>(
id: string,
opts?: AggregateGroupByNearOptions<T, M>
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]>;
/**
* Aggregate metrics over the objects returned by a near text vector search on this collection.
* Aggregate metrics over the objects grouped by a specified property and returned by a near text vector search on this collection.
*
* At least one of `certainty`, `distance`, or `object_limit` must be specified here for the vector search.
*
* This method requires a vectorizer capable of handling text, e.g. `text2vec-contextionary`, `text2vec-openai`, etc.
*
* @param {string | string[]} query The text to search for.
* @param {AggregateGroupByNearOptions<T, M>} [opts] The options for the request.
* @param {AggregateGroupByNearOptions<T, M>} opts The options for the request.
* @returns {Promise<AggregateGroupByResult<T, M>[]>} The aggregated metrics for the objects returned by the vector search.
*/
nearText<M extends PropertiesMetrics<T>>(
query: string | string[],
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]>;
/**
* Aggregate metrics over the objects returned by a near vector search on this collection.
* Aggregate metrics over the objects grouped by a specified property and returned by a near vector search on this collection.
*
* At least one of `certainty`, `distance`, or `object_limit` must be specified here for the vector search.
*
* This method requires that the objects in the collection have associated vectors.
*
* @param {number[]} vector The vector to search for.
* @param {AggregateGroupByNearOptions<T, M>} [opts] The options for the request.
* @param {AggregateGroupByNearOptions<T, M>} opts The options for the request.
* @returns {Promise<AggregateGroupByResult<T, M>[]>} The aggregated metrics for the objects returned by the vector search.
*/
nearVector<M extends PropertiesMetrics<T>>(
vector: number[],
opts?: AggregateGroupByNearOptions<T, M>
opts: AggregateGroupByNearOptions<T, M>
): Promise<AggregateGroupByResult<T, M>[]>;
/**
* Aggregate metrics over all the objects in this collection without any vector search.
* Aggregate metrics over all the objects in this collection grouped by a specified property without any vector search.
*
* @param {AggregateGroupByOptions<T, M>} [opts] The options for the request.
* @returns {Promise<AggregateGroupByResult<T, M>[]>} The aggregated metrics for the objects in the collection.
Expand Down
Loading
Loading