Skip to content

Commit

Permalink
refactor: deprecated ExactMatchFilter and use MetadataFilter with man…
Browse files Browse the repository at this point in the history
…y operator support
  • Loading branch information
thucpn committed Jul 11, 2024
1 parent 4205967 commit 12d80c6
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 20 deletions.
4 changes: 2 additions & 2 deletions examples/metadata-filter/simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ async function main() {
{
key: "private",
value: "false",
filterType: "ExactMatch",
operator: "==",
},
{
key: "dogId",
value: "3",
filterType: "ExactMatch",
operator: "==",
},
],
},
Expand Down
5 changes: 4 additions & 1 deletion packages/llamaindex/src/storage/vectorStore/PGVectorStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,10 @@ export class PGVectorStore
query.filters?.filters.forEach((filter, index) => {
const paramIndex = params.length + 1;
whereClauses.push(`metadata->>'${filter.key}' = $${paramIndex}`);
params.push(filter.value);
// TODO: support filter with other operators
if (!Array.isArray(filter.value)) {
params.push(filter.value);
}
});

const where =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
VectorStoreBase,
type ExactMatchFilter,
type IEmbedModel,
type MetadataFilter,
type MetadataFilters,
type VectorStoreNoEmbedModel,
type VectorStoreQuery,
Expand Down Expand Up @@ -199,8 +199,12 @@ export class PineconeVectorStore
}

toPineconeFilter(stdFilters?: MetadataFilters) {
return stdFilters?.filters?.reduce((carry: any, item: ExactMatchFilter) => {
carry[item.key] = item.value;
return stdFilters?.filters?.reduce((carry: any, item: MetadataFilter) => {
// Use MetadataFilter with EQ operator to replace ExactMatchFilter
// TODO: support filter with other operators
if (item.operator === "==") {
carry[item.key] = item.value;
}
return carry;
}, {});
}
Expand Down
29 changes: 18 additions & 11 deletions packages/llamaindex/src/storage/vectorStore/SimpleVectorStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import {
import { exists } from "../FileSystem.js";
import { DEFAULT_PERSIST_DIR } from "../constants.js";
import {
FilterOperator,
VectorStoreBase,
VectorStoreQueryMode,
type IEmbedModel,
type MetadataFilter,
type VectorStoreNoEmbedModel,
type VectorStoreQuery,
type VectorStoreQueryResult,
Expand All @@ -26,10 +28,12 @@ const LEARNER_MODES = new Set<VectorStoreQueryMode>([

const MMR_MODE = VectorStoreQueryMode.MMR;

type MetadataValue = Record<string, any>;

class SimpleVectorStoreData {
embeddingDict: Record<string, number[]> = {};
textIdToRefDocId: Record<string, string> = {};
metadataDict: Record<string, Record<string, any>> = {};
metadataDict: Record<string, MetadataValue> = {};
}

export class SimpleVectorStore
Expand Down Expand Up @@ -105,27 +109,30 @@ export class SimpleVectorStore
}> {
const items = Object.entries(this.data.embeddingDict);

const metadataLookup = {
ExactMatch: (
metadata: Record<string, any>,
key: string,
value: string | number,
) => {
return String(metadata[key]) === value.toString(); // compare as string
const operatorToFilterFn: Record<
FilterOperator,
(
input: Omit<MetadataFilter, "operator"> & {
metadata: MetadataValue;
},
) => boolean
> = {
"==": (input) => {
return String(input.metadata[input.key]) === input.value.toString(); // compare as string
},
};

const queryFilterFn = (nodeId: string) => {
if (!query.filters) return true;
const filters = query.filters.filters;
for (const filter of filters) {
const { key, value, filterType } = filter;
const metadataLookupFn = metadataLookup[filterType];
const { key, value, operator } = filter;
const metadataLookupFn = operatorToFilterFn[operator];
const metadata = this.data.metadataDict[nodeId];
const isMatch =
metadataLookupFn &&
metadata &&
metadataLookupFn(metadata, key, value);
metadataLookupFn({ metadata, key, value });
if (!isMatch) return false; // TODO: handle condition OR AND
}
return true;
Expand Down
36 changes: 34 additions & 2 deletions packages/llamaindex/src/storage/vectorStore/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,51 @@ export enum VectorStoreQueryMode {
MMR = "mmr",
}

/**
* @deprecated Use MetadataFilter with operator EQ instead
*/
export interface ExactMatchFilter {
filterType: "ExactMatch";
key: string;
value: string | number;
}

export enum FilterOperator {
EQ = "==", // default operator (string, number)
// GT = ">", // greater than (number)
// LT = "<", // less than (number)
// NE = "!=", // not equal to (string, number)
// GTE = ">=", // greater than or equal to (number)
// LTE = "<=", // less than or equal to (number)
// IN = "in", // In array (string or number)
// NIN = "nin", // Not in array (string or number)
// ANY = "any", // Contains any (array of strings)
// ALL = "all", // Contains all (array of strings)
// TEXT_MATCH = "text_match", // full text match (allows you to search for a specific substring, token or phrase within the text field)
// CONTAINS = "contains", // metadata array contains value (string or number)
}

export enum FilterCondition {
AND = "and",
OR = "or",
}

export type MetadataFilterValue = string | number | string[] | number[];

export interface MetadataFilter {
key: string;
value: MetadataFilterValue;
operator: `${FilterOperator}`; // ==, any, all,...
}

export interface MetadataFilters {
filters: ExactMatchFilter[];
filters: Array<MetadataFilter>;
condition?: `${FilterCondition}`; // and, or
}

export interface VectorStoreQuerySpec {
query: string;
filters: ExactMatchFilter[];
filters: MetadataFilter[];
topK?: number;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe("SimpleVectorStore", () => {
{
key: "private",
value: "false",
filterType: "ExactMatch",
operator: "==",
},
],
},
Expand Down

0 comments on commit 12d80c6

Please sign in to comment.