-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat(redis): Advanced pre-filter for document metadata #9240
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
Open
tishun
wants to merge
3
commits into
langchain-ai:main
Choose a base branch
from
tishun:topic/tishun/redis-vector-store-improvements
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+4,891
−918
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
275 changes: 275 additions & 0 deletions
275
examples/src/langchain-classic/indexes/vector_stores/redis/redis_advanced_filtering.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,275 @@ | ||
| /** | ||
| * Advanced Redis Vector Store Filtering Examples | ||
| * | ||
| * This example demonstrates all the advanced filtering capabilities of RedisVectorStore: | ||
| * - Tag filters for categorical data | ||
| * - Numeric filters for ranges and comparisons | ||
| * - Text filters for full-text search | ||
| * - Geo filters for location-based queries | ||
| * - Timestamp filters for date/time queries | ||
| * - Complex combinations with AND/OR logic | ||
| * - Custom filters with raw RediSearch query syntax | ||
| * | ||
| * Note: Timestamps are stored as numeric fields (Unix epoch timestamps). | ||
| * Date objects are automatically converted during serialization and returned | ||
| * as numbers during deserialization. | ||
| */ | ||
|
|
||
| import { createClient } from "redis"; | ||
| import { OpenAIEmbeddings } from "@langchain/openai"; | ||
| import { | ||
| RedisVectorStore, | ||
| Tag, | ||
| Num, | ||
| Text, | ||
| Geo, | ||
| Timestamp, | ||
| Custom, | ||
| } from "@langchain/redis"; | ||
| import { Document } from "@langchain/core/documents"; | ||
|
|
||
| // Connect to Redis | ||
| const client = createClient({ | ||
| url: process.env.REDIS_URL ?? "redis://localhost:6379", | ||
| }); | ||
| await client.connect(); | ||
|
|
||
| // Sample documents with rich metadata | ||
| const docs = [ | ||
| new Document({ | ||
| metadata: { | ||
| category: "electronics", | ||
| price: 299.99, | ||
| title: "Wireless Bluetooth Headphones", | ||
| location: [-122.4194, 37.7749], // San Francisco | ||
| created_at: new Date("2023-01-15"), | ||
| brand: "TechCorp", | ||
| rating: 4.5, | ||
| }, | ||
| pageContent: | ||
| "High-quality wireless Bluetooth headphones with noise cancellation", | ||
| }), | ||
| new Document({ | ||
| metadata: { | ||
| category: "books", | ||
| price: 24.99, | ||
| title: "JavaScript Programming Guide", | ||
| location: [-74.006, 40.7128], // New York | ||
| created_at: new Date("2023-03-20"), | ||
| author: "John Smith", | ||
| pages: 450, | ||
| }, | ||
| pageContent: | ||
| "Comprehensive guide to modern JavaScript programming techniques", | ||
| }), | ||
| new Document({ | ||
| metadata: { | ||
| category: "electronics", | ||
| price: 899.99, | ||
| title: "4K Smart TV", | ||
| location: [-118.2437, 34.0522], // Los Angeles | ||
| created_at: new Date("2023-02-10"), | ||
| brand: "ViewTech", | ||
| screen_size: 55, | ||
| }, | ||
| pageContent: | ||
| "Ultra HD 4K Smart TV with streaming capabilities and voice control", | ||
| }), | ||
| new Document({ | ||
| metadata: { | ||
| category: "books", | ||
| price: 19.99, | ||
| title: "Machine Learning Basics", | ||
| location: [-122.4194, 37.7749], // San Francisco | ||
| created_at: new Date("2023-04-05"), | ||
| author: "Jane Doe", | ||
| pages: 320, | ||
| }, | ||
| pageContent: | ||
| "Introduction to machine learning concepts and practical applications", | ||
| }), | ||
| ]; | ||
|
|
||
| // Create vector store with metadata schema for proper indexing | ||
| const vectorStore = await RedisVectorStore.fromDocuments( | ||
| docs, | ||
| new OpenAIEmbeddings(), | ||
| { | ||
| redisClient: client, | ||
| indexName: "advanced_products", | ||
| customSchema: [ | ||
| { name: "category", type: "tag" }, | ||
| { name: "price", type: "numeric", options: { sortable: true } }, | ||
| { name: "title", type: "text", options: { weight: 2.0 } }, | ||
| { name: "location", type: "geo" }, | ||
| // Timestamps are stored as numeric fields (Unix epoch timestamps) | ||
| { name: "created_at", type: "numeric", options: { sortable: true } }, | ||
| { name: "brand", type: "tag" }, | ||
| { name: "author", type: "tag" }, | ||
| { name: "rating", type: "numeric" }, | ||
| { name: "pages", type: "numeric" }, | ||
| { name: "screen_size", type: "numeric" }, | ||
| ], | ||
| } | ||
| ); | ||
|
|
||
| console.log("=== Advanced Redis Vector Store Filtering Examples ===\n"); | ||
|
|
||
| // Example 1: Simple tag filtering | ||
| console.log("1. Simple tag filtering - Electronics only:"); | ||
| const electronicsFilter = Tag("category").eq("electronics"); | ||
| const electronicsResults = await vectorStore.similaritySearch( | ||
| "high quality device", | ||
| 5, | ||
| electronicsFilter | ||
| ); | ||
| console.log(`Found ${electronicsResults.length} electronics items`); | ||
| electronicsResults.forEach((doc) => | ||
| console.log(`- ${doc.metadata.title} ($${doc.metadata.price})`) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 2: Numeric range filtering | ||
| console.log("2. Numeric range filtering - Products between $20-$500:"); | ||
| const priceFilter = Num("price").between(20, 500); | ||
| const priceResults = await vectorStore.similaritySearch( | ||
| "quality product", | ||
| 5, | ||
| priceFilter | ||
| ); | ||
| console.log(`Found ${priceResults.length} products in price range`); | ||
| priceResults.forEach((doc) => | ||
| console.log(`- ${doc.metadata.title} ($${doc.metadata.price})`) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 3: Text search filtering | ||
| console.log("3. Text search filtering - Titles containing 'programming':"); | ||
| const textFilter = Text("title").wildcard("*programming*"); | ||
| const textResults = await vectorStore.similaritySearch( | ||
| "learning guide", | ||
| 5, | ||
| textFilter | ||
| ); | ||
| console.log(`Found ${textResults.length} programming-related items`); | ||
| textResults.forEach((doc) => | ||
| console.log(`- ${doc.metadata.title} by ${doc.metadata.author || "N/A"}`) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 4: Geographic filtering | ||
| console.log("4. Geographic filtering - Items within 50km of San Francisco:"); | ||
| const geoFilter = Geo("location").within(-122.4194, 37.7749, 50, "km"); | ||
| const geoResults = await vectorStore.similaritySearch( | ||
| "local products", | ||
| 5, | ||
| geoFilter | ||
| ); | ||
| console.log(`Found ${geoResults.length} items near San Francisco`); | ||
| geoResults.forEach((doc) => | ||
| console.log(`- ${doc.metadata.title} (${doc.metadata.location})`) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 5: Timestamp filtering | ||
| console.log("5. Timestamp filtering - Items created after March 1, 2023:"); | ||
| const timestampFilter = Timestamp("created_at").gt(new Date("2023-03-01")); | ||
| const timestampResults = await vectorStore.similaritySearch( | ||
| "recent items", | ||
| 5, | ||
| timestampFilter | ||
| ); | ||
| console.log(`Found ${timestampResults.length} recent items`); | ||
| timestampResults.forEach((doc) => { | ||
| // created_at is stored as a Unix epoch timestamp (number) | ||
| // Convert it back to a Date for display | ||
| const createdDate = new Date((doc.metadata.created_at as number) * 1000); | ||
| console.log(`- ${doc.metadata.title} (${createdDate.toDateString()})`); | ||
| }); | ||
| console.log(); | ||
|
|
||
| // Example 6: Complex combined filtering | ||
| console.log("6. Complex filtering - Electronics under $400 in California:"); | ||
| const complexFilter = Tag("category") | ||
| .eq("electronics") | ||
| .and(Num("price").lt(400)) | ||
| .and(Geo("location").within(-119.4179, 36.7783, 500, "km")); // California center | ||
|
|
||
| const complexResults = await vectorStore.similaritySearch( | ||
| "affordable electronics", | ||
| 5, | ||
| complexFilter | ||
| ); | ||
| console.log( | ||
| `Found ${complexResults.length} affordable electronics in California` | ||
| ); | ||
| complexResults.forEach((doc) => | ||
| console.log( | ||
| `- ${doc.metadata.title} ($${doc.metadata.price}) at ${doc.metadata.location}` | ||
| ) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 7: OR filtering | ||
| console.log("7. OR filtering - Books OR items under $30:"); | ||
| const orFilter = Tag("category").eq("books").or(Num("price").lt(30)); | ||
| const orResults = await vectorStore.similaritySearch( | ||
| "affordable items", | ||
| 5, | ||
| orFilter | ||
| ); | ||
| console.log(`Found ${orResults.length} books or cheap items`); | ||
| orResults.forEach((doc) => | ||
| console.log( | ||
| `- ${doc.metadata.title} (${doc.metadata.category}, $${doc.metadata.price})` | ||
| ) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 8: Multiple tag values | ||
| console.log("8. Multiple tag values - TechCorp OR ViewTech brands:"); | ||
| const multiTagFilter = Tag("brand").eq(["TechCorp", "ViewTech"]); | ||
| const multiTagResults = await vectorStore.similaritySearch( | ||
| "branded products", | ||
| 5, | ||
| multiTagFilter | ||
| ); | ||
| console.log(`Found ${multiTagResults.length} items from specified brands`); | ||
| multiTagResults.forEach((doc) => | ||
| console.log(`- ${doc.metadata.title} by ${doc.metadata.brand}`) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 9: Negation filtering | ||
| console.log("9. Negation filtering - NOT electronics:"); | ||
| const negationFilter = Tag("category").ne("electronics"); | ||
| const negationResults = await vectorStore.similaritySearch( | ||
| "non-electronic items", | ||
| 5, | ||
| negationFilter | ||
| ); | ||
| console.log(`Found ${negationResults.length} non-electronic items`); | ||
| negationResults.forEach((doc) => | ||
| console.log(`- ${doc.metadata.title} (${doc.metadata.category})`) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Example 10: Custom filter with raw RediSearch syntax | ||
| console.log("10. Custom filter - Raw RediSearch query syntax:"); | ||
| const customFilter = Custom("(@category:{electronics} @price:[0 400])"); | ||
| const customResults = await vectorStore.similaritySearch( | ||
| "affordable tech", | ||
| 5, | ||
| customFilter | ||
| ); | ||
| console.log(`Found ${customResults.length} affordable electronics`); | ||
| customResults.forEach((doc) => | ||
| console.log(`- ${doc.metadata.title} ($${doc.metadata.price})`) | ||
| ); | ||
| console.log(); | ||
|
|
||
| // Cleanup | ||
| await vectorStore.delete({ deleteAll: true }); | ||
| await client.disconnect(); | ||
|
|
||
| console.log("\n=== Advanced filtering examples completed! ==="); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.