Exploring Retrievers with LangChain
Data Mastery Series — Episode 38: LangChain Website (Part 13 )
Exploring Retrievers with LangChain
Data Mastery Series — Episode 38: LangChain Website (Part 13 )

Connect with me and follow our journey: Linkedin, Facebook
Welcome to Episode 38 of the Data Mastery Series! Today, we continue our exploration of retrievers, diving into advanced techniques that further enhance information retrieval in LangChain-powered workflows.
Before we dive in, let’s recap our journey so far:
- Part 1: LangChain Model I/O Basics
- Part 2–3: Prompt Templates and Few-Shot Prompts
- Part 4–6: Deep Dive into Chat Models (Part 1, Part 2, Part 3)
- Part 7: LLM Fundamentals
- Part 8: Output Parsers
- Part 9: Document Loaders
- Part 10: Text Splitter
- Part 11: Embeddings and Vector Stores
- Part 12: Retrievers (Part 1)
Note:This post is inspired by insights from the official LangChain documentation and represents my practical learning journey.
In the previous episode, we covered Vectorstore Retrievers, ParentDocument Retrievers, and Multi-Vector Retrievers. In this episode, we’ll delve into Self-Query Retrievers, Contextual Compression, and Time-Weighted Vectorstore Retrievers.
4. Self-Query Retrievers: Querying Metadata and Content
A self-querying retriever is like having an AI assistant that can refine your questions before searching for answers. Instead of just relying on keyword matching, it can understand the underlying structure of your query and use metadata to filter information more accurately. Think of it as adding precision to your search.
- Index Type: Vectorstore
- Uses an LLM: Yes
- Use Cases: Ideal when your queries require filtering by metadata (like author, date, or category) rather than just relying on semantic content matching.
If a user’s question relates more to document metadata than the content, Self Query is the way to go.

Photo from web: https://python.langchain.com/v0.1/docs/modules/data%5Fconnection/retrievers/self%5Fquery/
Example - Self Query Retrievers
Load and split documents
loaders = [
TextLoader("../../Tortoise and the Hare.txt"),
TextLoader("../../ลูกหมูสามตัว.txt"),
]
docs = []
for loader in loaders:
docs.extend(loader.load())
Create documents with metadata
docs_with_metadata = [
Document(
page_content=docs[0].page_content,
metadata={"title": "ลูกหมูสามตัว", "genre": "children", "year": 1990, "language": "Thai"}
),
Document(
page_content=docs[1].page_content,
metadata={"title": "Tortoise and the Hare", "genre": "children", "year": 1995, "language": "English"}
)
]
Define metadata fields
metadata_field_info = [
AttributeInfo(
name="title",
description="The title of the story",
type="string",
),
AttributeInfo(
name="genre",
description="The genre of the story, usually 'children'",
type="string",
),
AttributeInfo(
name="year",
description="The year the story was published",
type="integer",
),
AttributeInfo(
name="language",
description="The language of the story",
type="string",
),
]
Create VectorStore
vectorstore = Chroma.from_documents(docs_with_metadata, OpenAIEmbeddings(api_key=OPENAI_API_KEY))
Initialize SelfQueryRetriever
document_content_description = "A brief summary of the story"
llm = ChatOpenAI(temperature=0, api_key=OPENAI_API_KEY)
retriever = SelfQueryRetriever.from_llm(
llm,
vectorstore,
document_content_description,
metadata_field_info,
# enable_limit=True, # Filter K (optional)
)
result = retriever.invoke("I want a children story in Thai")
Example of output of result
"""
Story 1:
ลูกหมูสามตัว
กาลครั้งหนึ่งนานมาแล้ว มีแม่หมูอยู่กับลูกหมูสามตัว ลูกหมูทั้งสามโตหมดแล้ว ถึงเวลาที่พวกเขาต้องสร้างบ้านของตัวเองและออกไปผจญภัยในโลกกว้าง
ลูกหมูโต ชื่อ ข้าวสวย- พี่ชายคนโต เป็นหมูที่ค่อนข้างขี้เกียจ เขาตัดสินใจสร้างบ้านอย่างรวดเร็ว เจอกองฟางข้าวใกล้ๆ นึกในใจว่า "แค่นี้ก็พอแล้ว!" จากนั้นเขาก็รีบๆ สร้างบ้านฟางฟางที่กางออกง่ายๆ
ลูกหมูรอง ชื่อ ข้าวหอม- น้องชายคนที่สอง ไม่ได้ขี้เกียจเท่าพี่ชาย เขาตัดสินใจสร้างบ้านที่แข็งแรงกว่า เขาเก็บกิ่งไม้และก้านไม้จากป่ามาสร้างบ้านไม้ มันไม่ใช่บ้านที่แข็งแรงที่สุด แต่เขาคิดว่ามันก็น่าจะเพียงพอ
ลูกหมูเล็กชื่อ ข้าวสุก - น้องชายคนสุดท้อง ขึ้นชื่อเรื่องการทำงานหนักและวางแผน เขาต้องการบ้านที่จะทำให้เขามีความปลอดภัยอย่างแท้จริง เขาใช้เวลาหลายวันในการเก็บอิฐที่แข็งแรงและสร้างบ้านอิฐที่แข็งแรงอย่างระมัดระวัง เขายังสร้างปล่องไฟและประตูที่เหมาะสมพร้อมกับกุญแจที่แข็งแรง
วันแดดสดใสวันหนึ่ง มีหมาป่าตัวใหญ่ใจร้ายมีนามว่า แกงส้ม เดินเลาะเลียบไปตามทาง มันได้กลิ่นหอมกรุ่นของหมูย่างและเดินตามกลิ่นนั้นไปจนถึงบ้านฟางของลูกหมูตัวแรก
"ลูกหมู ๆ เปิดประตูให้ข้าเข้าไปสิ!" หมาป่าคำราม
"ไม่! ข้าจะไม่ให้เจ้าเข้ามา!" ลูกหมูตัวเล็กตกใจร้องเสียงแหลม
หมาป่าสูดลมพ่นออกแรง ๆ เป่าบ้านฟางจนพังทลาย! ลูกหมูตัวเล็กกรี๊ดร้องและวิ่งหนีเร็วที่สุดเท่าที่จะวิ่ง
เขาวิ่งไปที่บ้านไม้ของพี่ชาย หมาป่าวิ่งตามมาติดๆ และเมื่อมาถึงบ้านไม้ มันก็ร้องขอ "ลูกหมู ๆ เปิดประตูให้ข้าเข้าไปสิ!"
"ไม่! พวกเราจะไม่ให้เจ้าเข้ามา!" ลูกหมูทั้งสองตัวร้องออกมาพร้อมกัน
หมาป่าสูดลมพ่นออกแรง ๆ เป่าบ้านไม้จนพังทลาย! ลูกหมูทั้งสองตัวกรี๊ดร้องและวิ่งหนีเร็วที่สุดเท่าที่จะวิ่ง ไปที่บ้านอิฐของน้องชายคนสุดท้อง
หมาป่าตอนนี้หิวโซกว่าเดิม วิ่งตามพวกมันไป เมื่อมาถึงบ้านอิฐ มันตะโกนว่า "ลูกหมู ๆ เปิดประตูให้ข้าเข้าไปสิ!"
"ไม่! พวกเราจะไม่ให้เจ้าเข้ามา!" ลูกหมูทั้งสามตัวตะโกนออกมาพร้อมกัน ตอนนี้พวกเขารู้สึกกล้าหาญมากขึ้นเพราะพวกเขาปลอดภัยอยู่ข้างใน
หมาป่าสูดลมพ่นออกแรง ๆ เป่าบ้านอิฐจนสุดแรงเกิด มันเป่าแรงจนหน้าแดง แต่บ้านอิฐก็ไม่ขยับเขยื้อน หมาป่าหงุดหงิดและพ่ายแพ้ ยอมแพ้และเดินโซซัดเซไปในป่า
ลูกหมูทั้งสามตัว ปลอดภัยอยู่ในบ้านอิฐ พวกเขาได้เรียนบทเรียนอันมีค่าในวันนั้น ความขยันหมั่นเพียรและการวางแผนนั้นสำคัญ และรากฐานที่แข็งแกร่งสามารถช่วยให้คุณปลอดภัยจากอันตราย พวกเขาอยู่ด้วยกันอย่างมีความสุขตลอดไปในบ้านอิฐที่แข็งแรง ไม่เคยลืมความสำคัญของการเตรียมตัว
"""
5. Contextual Compression: Focused and Relevant Retrieval
Imagine you’re searching through a huge book for a specific quote. You wouldn’t want to read the entire book, just the relevant parts, right? That’s what contextual compression does for AI. It narrows down the information returned by retrievers to the most relevant bits, leading to faster and more focused responses.
- Index Type: Flexible, can be used with various types of indices
- Uses an LLM: Optional
- Use Cases: When retrieved documents contain too much irrelevant information, potentially distracting LLMs.
The idea is simple: instead of immediately returning retrieved documents as-is, you can compress them using the context of the given query, so that only the relevant information is returned. “Compressing” here refers to both compressing the contents of an individual document and filtering out documents completely.
5.1) Vanilla Vector Store Retriever
First, we will show what the return data from the normal retriever look like.
Example - Parent Document Retriever - Vanilla Vector Store Retriever
Load and split documents
loaders = [
TextLoader("../../Tortoise and the Hare.txt"),
TextLoader("../../ลูกหมูสามตัว.txt"),
]
documents = []
for loader in loaders:
documents.extend(loader.load())
Helper function for printing docs
def pretty_print_docs(docs):
print(
f"\n{'-' * 100}\n".join(
[f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]
)
)
Split documents into smaller chunks
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
Create retriever
retriever = FAISS.from_documents(texts, OpenAIEmbeddings(api_key=OPENAI_API_KEY)).as_retriever()
Get documents from query
def pretty_print_docs(docs):
print(
f"\n{'-' * 100}\n".join(
[f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]
)
)
docs = retriever.invoke("What did the tortoise do in the race")
pretty_print_docs(docs)
Example of output of result
"""
Document 1:
Tortoise and the Hare
Deep within a sun-dappled clearing of the DC Forest, lived a hare named Piti, famed for his lightning speed. He would streak past the other animals, a blur of brown fur that left them breathless in his wake. One crisp morning, Piti was bragging about his agility, puffing out his chest and flicking his tail with unconcealed pride.
"There's no creature in this entire forest faster than me!" he declared, his voice echoing through the trees.
A slow, rumbling voice came from behind a nearby thicket. It was Donato, a tortoise known for his steady pace and unwavering determination.
"Speed isn't everything, Piti," Donato rumbled. "Even the slowest can achieve victory, if they set their mind to it."
Piti burst into laughter. "You? Win a race against me? Donato, that's the most ludicrous notion I've ever heard!"
Document 2:
He drifted off to sleep, picturing himself crossing the finish line first to a chorus of cheers. But time crawled by for the sleeping hare, while for Donato, it marched on relentlessly.
Donato, inch by inch, made his way towards the finish line. The animals, who had initially mocked him, now cheered him on, their voices echoing through the forest. They were impressed by his unwavering perseverance.
Finally, Donato, with a triumphant plod, crossed the finish line. Piti woke up with a start, his ears twitching in disbelief. He saw, to his utter humiliation, the crowd celebrating Donato's victory.
The hare had lost the race, not to speed, but to slow and steady determination. The cheers of the animals resonated through the DC Forest, a testament to the fact that slow and steady truly does win the race.
Document 3:
To everyone's surprise, Donato challenged Piti to a race. The other animals gathered around, buzzing with excitement at the prospect of such an unequal competition. Even the wise old owl hooted in amusement, his amber eyes twinkling with anticipation.
The race began. Piti shot off like a furry bullet, leaving Donato in a cloud of dust. The animals cheered for the hare, certain of his victory. But Piti, brimming with overconfidence, spotted a patch of wildflowers bursting with color. He darted off the track, unable to resist the temptation of a tasty treat.
Meanwhile, Donato plodded on steadily, never stopping, never wavering. He may have been slow, but his determination burned bright.
Back on the track, Piti, feeling sluggish from his snack, decided to take a nap under the shade of a towering oak. "Old Donato won't catch up to me anyway," he thought arrogantly.
Document 4:
"ลูกหมู ๆ เปิดประตูให้ข้าเข้าไปสิ!" หมาป่าคำราม
"ไม่! ข้าจะไม่ให้เจ้าเข้ามา!" ลูกหมูตัวเล็กตกใจร้องเสียงแหลม
หมาป่าสูดลมพ่นออกแรง ๆ เป่าบ้านฟางจนพังทลาย! ลูกหมูตัวเล็กกรี๊ดร้องและวิ่งหนีเร็วที่สุดเท่าที่จะวิ่ง
เขาวิ่งไปที่บ้านไม้ของพี่ชาย หมาป่าวิ่งตามมาติดๆ และเมื่อมาถึงบ้านไม้ มันก็ร้องขอ "ลูกหมู ๆ เปิดประตูให้ข้าเข้าไปสิ!"
"ไม่! พวกเราจะไม่ให้เจ้าเข้ามา!" ลูกหมูทั้งสองตัวร้องออกมาพร้อมกัน
หมาป่าสูดลมพ่นออกแรง ๆ เป่าบ้านไม้จนพังทลาย! ลูกหมูทั้งสองตัวกรี๊ดร้องและวิ่งหนีเร็วที่สุดเท่าที่จะวิ่ง ไปที่บ้านอิฐของน้องชายคนสุดท้อง
หมาป่าตอนนี้หิวโซกว่าเดิม วิ่งตามพวกมันไป เมื่อมาถึงบ้านอิฐ มันตะโกนว่า "ลูกหมู ๆ เปิดประตูให้ข้าเข้าไปสิ!"
"ไม่! พวกเราจะไม่ให้เจ้าเข้ามา!" ลูกหมูทั้งสามตัวตะโกนออกมาพร้อมกัน ตอนนี้พวกเขารู้สึกกล้าหาญมากขึ้นเพราะพวกเขาปลอดภัยอยู่ข้างใน
หมาป่าสูดลมพ่นออกแรง ๆ เป่าบ้านอิฐจนสุดแรงเกิด มันเป่าแรงจนหน้าแดง แต่บ้านอิฐก็ไม่ขยับเขยื้อน หมาป่าหงุดหงิดและพ่ายแพ้ ยอมแพ้และเดินโซซัดเซไปในป่า
"""
5.2) Contextual Compression with an LLMChainExtractor
This method uses an LLM chain to extract only the content from each retrieved document that is most relevant to the query, filtering out the rest.
Example - Parent Document Retriever - Contextual Compression Retriever
Load and split documents
loaders = [
TextLoader("../../Tortoise and the Hare.txt"),
TextLoader("../../ลูกหมูสามตัว.txt"),
]
documents = []
for loader in loaders:
documents.extend(loader.load())
Split documents
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
Create retriever
retriever = FAISS.from_documents(texts, OpenAIEmbeddings(api_key=OPENAI_API_KEY)).as_retriever()
Create Contextual Compression
llm = OpenAI(temperature=0, api_key=OPENAI_API_KEY)
compressor = LLMChainExtractor.from_llm(llm)
Initialize ContextualCompressionRetriever
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor, base_retriever=retriever
)
Set the question
question = "What did the tortoise do in the race"
compressed_docs = compression_retriever.invoke(question)
pretty_print_docs(compressed_docs)
Example of output of result
"""
Document 1:
Tortoise and the Hare
Donato, a tortoise known for his steady pace and unwavering determination.
"Speed isn't everything, Piti," Donato rumbled. "Even the slowest can achieve victory, if they set their mind to it."
Document 2:
Donato, inch by inch, made his way towards the finish line. The animals, who had initially mocked him, now cheered him on, their voices echoing through the forest. They were impressed by his unwavering perseverance.
Finally, Donato, with a triumphant plod, crossed the finish line.
Document 3:
- Donato challenged Piti to a race.
- The race began.
- Piti shot off like a furry bullet, leaving Donato in a cloud of dust.
- Piti, brimming with overconfidence, spotted a patch of wildflowers bursting with color.
- He darted off the track, unable to resist the temptation of a tasty treat.
- Meanwhile, Donato plodded on steadily, never stopping, never wavering.
- Piti, feeling sluggish from his snack, decided to take a nap under the shade of a towering oak.
"""
More built-in compressors: filters
5.3) Contextual Compression with an LLMChainFilter
This compressor is a simpler approach, using an LLM to decide which of the initially returned documents to filter out, without altering the document contents.
Example - Parent Document Retriever - LLMChainFilter
Load and split documents
loaders = [
TextLoader("../../Tortoise and the Hare.txt"),
TextLoader("../../ลูกหมูสามตัว.txt"),
]
documents = []
for loader in loaders:
documents.extend(loader.load())
Split documents
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
Create retriever
retriever = FAISS.from_documents(texts, OpenAIEmbeddings(api_key=OPENAI_API_KEY)).as_retriever()
Create LLMChainFilter
llm = OpenAI(temperature=0, api_key=OPENAI_API_KEY)
_filter = LLMChainFilter.from_llm(llm)
Initialize ContextualCompressionRetriever
compression_retriever = ContextualCompressionRetriever(
base_compressor=_filter, base_retriever=retriever
)
Set the question
question = "What did the tortoise do in the race"
compressed_docs = compression_retriever.invoke(question)
pretty_print_docs(compressed_docs)
Example of output of result
"""
Document 1:
Tortoise and the Hare
Deep within a sun-dappled clearing of the DC Forest, lived a hare named Piti, famed for his lightning speed. He would streak past the other animals, a blur of brown fur that left them breathless in his wake. One crisp morning, Piti was bragging about his agility, puffing out his chest and flicking his tail with unconcealed pride.
"There's no creature in this entire forest faster than me!" he declared, his voice echoing through the trees.
A slow, rumbling voice came from behind a nearby thicket. It was Donato, a tortoise known for his steady pace and unwavering determination.
"Speed isn't everything, Piti," Donato rumbled. "Even the slowest can achieve victory, if they set their mind to it."
Piti burst into laughter. "You? Win a race against me? Donato, that's the most ludicrous notion I've ever heard!"
Document 2:
He drifted off to sleep, picturing himself crossing the finish line first to a chorus of cheers. But time crawled by for the sleeping hare, while for Donato, it marched on relentlessly.
Donato, inch by inch, made his way towards the finish line. The animals, who had initially mocked him, now cheered him on, their voices echoing through the forest. They were impressed by his unwavering perseverance.
Finally, Donato, with a triumphant plod, crossed the finish line. Piti woke up with a start, his ears twitching in disbelief. He saw, to his utter humiliation, the crowd celebrating Donato's victory.
The hare had lost the race, not to speed, but to slow and steady determination. The cheers of the animals resonated through the DC Forest, a testament to the fact that slow and steady truly does win the race.
Document 3:
To everyone's surprise, Donato challenged Piti to a race. The other animals gathered around, buzzing with excitement at the prospect of such an unequal competition. Even the wise old owl hooted in amusement, his amber eyes twinkling with anticipation.
The race began. Piti shot off like a furry bullet, leaving Donato in a cloud of dust. The animals cheered for the hare, certain of his victory. But Piti, brimming with overconfidence, spotted a patch of wildflowers bursting with color. He darted off the track, unable to resist the temptation of a tasty treat.
Meanwhile, Donato plodded on steadily, never stopping, never wavering. He may have been slow, but his determination burned bright.
Back on the track, Piti, feeling sluggish from his snack, decided to take a nap under the shade of a towering oak. "Old Donato won't catch up to me anyway," he thought arrogantly.
"""
5.4) Contextual Compression with an EmbeddingsFilter
This method provides a cost-effective alternative by using embeddings to filter out documents that are not semantically similar to the query.
Example - Parent Document Retriever - EmbeddingsFilter
Load and split documents
loaders = [
TextLoader("../../Tortoise and the Hare.txt"),
TextLoader("../../ลูกหมูสามตัว.txt"),
]
documents = []
for loader in loaders:
documents.extend(loader.load())
Split documents
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
Create retriever
embeddings = OpenAIEmbeddings(api_key=OPENAI_API_KEY)
retriever = FAISS.from_documents(texts, embeddings).as_retriever()
Create EmbeddingsFilter by using OpenAIEmbeddings
embeddings_filter = EmbeddingsFilter(embeddings=embeddings, similarity_threshold=0.76)
Initialize ContextualCompressionRetriever
compression_retriever = ContextualCompressionRetriever(
base_compressor=embeddings_filter, base_retriever=retriever
)
Set the question
question = "What did the tortoise do in the race?"
compressed_docs = compression_retriever.invoke(question)
pretty_print_docs(compressed_docs)
Example of output of result
"""
Document 1:
Tortoise and the Hare
Deep within a sun-dappled clearing of the DC Forest, lived a hare named Piti, famed for his lightning speed. He would streak past the other animals, a blur of brown fur that left them breathless in his wake. One crisp morning, Piti was bragging about his agility, puffing out his chest and flicking his tail with unconcealed pride.
"There's no creature in this entire forest faster than me!" he declared, his voice echoing through the trees.
A slow, rumbling voice came from behind a nearby thicket. It was Donato, a tortoise known for his steady pace and unwavering determination.
"Speed isn't everything, Piti," Donato rumbled. "Even the slowest can achieve victory, if they set their mind to it."
Piti burst into laughter. "You? Win a race against me? Donato, that's the most ludicrous notion I've ever heard!"
Document 2:
He drifted off to sleep, picturing himself crossing the finish line first to a chorus of cheers. But time crawled by for the sleeping hare, while for Donato, it marched on relentlessly.
Donato, inch by inch, made his way towards the finish line. The animals, who had initially mocked him, now cheered him on, their voices echoing through the forest. They were impressed by his unwavering perseverance.
Finally, Donato, with a triumphant plod, crossed the finish line. Piti woke up with a start, his ears twitching in disbelief. He saw, to his utter humiliation, the crowd celebrating Donato's victory.
The hare had lost the race, not to speed, but to slow and steady determination. The cheers of the animals resonated through the DC Forest, a testament to the fact that slow and steady truly does win the race.
Document 3:
To everyone's surprise, Donato challenged Piti to a race. The other animals gathered around, buzzing with excitement at the prospect of such an unequal competition. Even the wise old owl hooted in amusement, his amber eyes twinkling with anticipation.
The race began. Piti shot off like a furry bullet, leaving Donato in a cloud of dust. The animals cheered for the hare, certain of his victory. But Piti, brimming with overconfidence, spotted a patch of wildflowers bursting with color. He darted off the track, unable to resist the temptation of a tasty treat.
Meanwhile, Donato plodded on steadily, never stopping, never wavering. He may have been slow, but his determination burned bright.
Back on the track, Piti, feeling sluggish from his snack, decided to take a nap under the shade of a towering oak. "Old Donato won't catch up to me anyway," he thought arrogantly.
"""
5.5) Stringing compressors and document transformers together
Using the DocumentCompressorPipeline, we can combine multiple compressors and document transformers in sequence.
Example - Parent Document Retriever - EmbeddingsFilter
Load and split documents
loaders = [
TextLoader("../../Tortoise and the Hare.txt"),
TextLoader("../../ลูกหมูสามตัว.txt"),
]
documents = []
for loader in loaders:
documents.extend(loader.load())
Split documents
text_splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=0, separator=". ")
texts = text_splitter.split_documents(documents)
Create retriever
embeddings = OpenAIEmbeddings(api_key=OPENAI_API_KEY)
retriever = FAISS.from_documents(texts, embeddings).as_retriever()
Create EmbeddingsRedundantFilter (delete duplicate document)
redundant_filter = EmbeddingsRedundantFilter(embeddings=embeddings)
relevant_filter = EmbeddingsFilter(embeddings=embeddings, similarity_threshold=0.76)
Create DocumentCompressorPipeline
pipeline_compressor = DocumentCompressorPipeline(
transformers=[text_splitter, redundant_filter, relevant_filter]
)
Initialize ContextualCompressionRetriever
compression_retriever = ContextualCompressionRetriever(
base_compressor=pipeline_compressor, base_retriever=retriever
)
Set the question
question = "What did the tortoise do in the race?"
compressed_docs = compression_retriever.invoke(question)
pretty_print_docs(compressed_docs)
Example of output of result
"""
Document 1:
Tortoise and the Hare
Deep within a sun-dappled clearing of the DC Forest, lived a hare named Piti, famed for his lightning speed. He would streak past the other animals, a blur of brown fur that left them breathless in his wake
Document 2:
It was Donato, a tortoise known for his steady pace and unwavering determination.
"Speed isn't everything, Piti," Donato rumbled. "Even the slowest can achieve victory, if they set their mind to it."
Piti burst into laughter
Document 3:
Even the wise old owl hooted in amusement, his amber eyes twinkling with anticipation.
The race began. Piti shot off like a furry bullet, leaving Donato in a cloud of dust. The animals cheered for the hare, certain of his victory
Document 4:
He saw, to his utter humiliation, the crowd celebrating Donato's victory.
The hare had lost the race, not to speed, but to slow and steady determination. The cheers of the animals resonated through the DC Forest, a testament to the fact that slow and steady truly does win the race.
"""
6) Time-Weighted Vector Store Retriever: Prioritizing Recency
Sometimes, recent information is more valuable than older data. The Time-Weighted Vector Store Retriever factors in the recency of the information when ranking results, ensuring that the most relevant and up-to-date documents are prioritized.
- Index Type: Vectorstore
- Uses an LLM: No
- Use Cases: When you need to retrieve the most recent and relevant information from a time-sensitive dataset.
The core formula is:
semantic_similarity + (1.0 — decay_rate) ^ hours_passed
Here, hours_passed refers to the time since the document was last accessed (not the creation time). Let’s examine with low and high decay rates.
6.1) Low Decay Rate
Setting a low decay rate (close to 0) means that memories are “remembered” for longer. A decay rate of 0 makes this retriever equivalent to a vector lookup.
Example - Time-weighted vector store retriever - Low decay rate
Define embedding model
embeddings_model = OpenAIEmbeddings(api_key=OPENAI_API_KEY)
Initialize vectorstore
embedding_size = 1536
index = faiss.IndexFlatL2(embedding_size)
vectorstore = FAISS(embeddings_model, index, InMemoryDocstore({}), {})
Initialize TimeWeightedVectorStoreRetriever with very low decay_rate
retriever = TimeWeightedVectorStoreRetriever(
vectorstore=vectorstore, decay_rate=0.0000000000000000000000001, k=1
)
Add documents with access times
yesterday = datetime.now() - timedelta(days=1)
retriever.add_documents(
[Document(page_content="hello world", metadata={"last_accessed_at": yesterday})]
)
retriever.add_documents([Document(page_content="hello foo")])
Retrieve and print result
result = retriever.invoke("hello world")
print(result)
Example of output
"""
[Document(metadata={'last_accessed_at': datetime.datetime(2024, 12, 29, 4, 55, 19, 937951), 'created_at': datetime.datetime(2024, 12, 29, 4, 55, 19, 67516), 'buffer_idx': 0}, page_content='hello world')]
"""
6.2) High Decay Rate
Conversely, a high decay rate (close to 1) means that the recency score quickly diminishes, making the retriever prioritize semantic similarity more.
Example - Time-weighted vector store retriever - High decay rate
Define embedding model
embeddings_model = OpenAIEmbeddings(api_key=OPENAI_API_KEY)
Initialize vectorstore
embedding_size = 1536
index = faiss.IndexFlatL2(embedding_size)
vectorstore = FAISS(embeddings_model, index, InMemoryDocstore({}), {})
Initialize TimeWeightedVectorStoreRetriever with high decay_rate
retriever = TimeWeightedVectorStoreRetriever(
vectorstore=vectorstore, decay_rate=0.999, k=1
)
Add documents with access times
yesterday = datetime.now() - timedelta(days=1)
retriever.add_documents(
[Document(page_content="hello world", metadata={"last_accessed_at": yesterday})]
)
retriever.add_documents([Document(page_content="hello foo")])
Retrieve and print result
result = retriever.invoke("hello world")
print(result)
Example of output
"""
[Document(metadata={'last_accessed_at': datetime.datetime(2024, 12, 29, 5, 53, 1, 467568), 'created_at': datetime.datetime(2024, 12, 29, 5, 53, 1, 134997), 'buffer_idx': 1}, page_content='hello foo')]
"""
Key Takeaways
In this episode, we explored:
- Self-Query Retrievers: Perfect for metadata and structured queries.
- Contextual Compression Retrievers: Ideal for refining noisy document sets.
- Time-Weighted Retrievers: Effective for time-sensitive retrieval needs.
In Episode 39, we’ll explore remaining other retrieval techniques such as Multi-Query Retriever, Ensemble and Long-Context Reorder. Stay tuned to unlock the next level of intelligent data retrieval! 🚀
Data Science Explore the world of data science with Donato_Story
Dashboard Discover the power of data visualization with Donato_Story
Donato_Journey Join me on my journey (Thai version)
Course_Review Discover the training courses with Donato_Story (Thai version)
Let’s Connect!
Your thoughts and feedback are invaluable. Feel free to share them in the comments or connect with me on
- Medium: medium.com/donato-story
- Facebook: web.facebook.com/DonatoStory
- Linkedin: linkedin.com/in/nattapong-thanngam
Originally published on Medium
Related
Chat with Document: A Closer Look at Splitting, Embeddings, and RAG
Data Mastery Series — Episode 21: The Chat with Document and Langchain Series (Part 2)
Chat with Document: Basics and Demonstrations
Data Mastery Series — Episode 20: The Chat with Document and Langchain Series (Part 1)
Continue Exploring Chat Models with LangChain
Data Mastery Series — Episode 31: LangChain Website (Part 6)
Continue Exploring Retrievers with LangChain
Data Mastery Series — Episode 39: LangChain Website (Part 14 )