Optimizing RAG Performance Through Advanced Chunking Techniques

Blog | February 26, 2024 | By Alagappan Ramanathan, Rahul S

Enhancing Efficiency: Advanced Chunking for RAG Performance

Mastering RAG Monitoring: Strategies for Success

In the world of Retrieval Augmented Generation (RAG) systems, chunking plays a pivotal role. It’s a process that can significantly influence the performance and effectiveness of your system. But what factors should you consider when deciding how to chunk your content? Let’s delve into six key considerations.

Let’s delve into six key considerations

1. Content Type

The first factor to consider is the type of content you’re processing for indexing. Are you dealing with lengthy documents such as articles or books, or are you working with shorter content like tweets or instant messages? The nature of the content determines which model would be most appropriate for your task and, as a result, influences the approach to chunking that should be employed.

2. Choice of Embedding Model

The embedding model you utilize, and the ideal chunk sizes for its optimal performance, is another crucial consideration. For instance, sentence-transformer models excel when applied to single sentences, whereas a model like text-embedding-ada-002 delivers superior results when working with chunks comprising 256 or 512 tokens.

3. Query Length and Complexity

What do you anticipate in terms of the length and complexity of user queries? Are they expected to be concise and focused or lengthy and intricate? This consideration may influence your approach to content chunking, ensuring a stronger alignment between the embedded query and the embedded content chunks.

4. Intended Application

The intended application for the retrieved results within your particular context is another important factor. Will they be employed for semantic search, question answering, summarization, or other specific purposes? For instance, if you plan to feed these results into another Language Model with a token limit, you’ll need to account for this constraint and adjust the chunk sizes accordingly to ensure they fit within the request to the Language Model.

5. Language Considerations

If your content is in multiple languages, you may need to consider a different chunking strategy, language-specific models, or preprocessing steps to ensure accurate indexing and chunking.

6. Real-time vs Batch Processing

Finally, depending on your application, you may need to decide between real-time indexing or batch processing to keep your content up-to-date and ensure efficient retrieval.


Now that we know the importance of why chunking is done, let’s delve into the world of Chunking methodologies and implementations.

Understanding RAG Performance Indicators

Exploring Advanced Chunking Techniques

Benefits of Optimizing RAG Performance

Implementing Advanced Chunking Strategies for RAG performance

Fixed-Size Chunking: A Deep Dive

Fixed-size chunking, also referred to as the Fixed-size overlapping sliding window method, offers a simple yet effective approach to text chunking. By dividing the text into fixed-size chunks based on character count, this method proves valuable in preliminary exploratory data analysis, where the aim is to gain a broad understanding of the text’s structure rather than delve into intricate semantic analysis. It finds relevance in scenarios where the text lacks a robust semantic structure, like certain raw data or logs. However, for more sophisticated tasks demanding precise context and semantic comprehension, such as sentiment analysis, question-answering systems, or text summarization, employing advanced text chunking techniques becomes imperative.

Fixed-size chunking boasts advantages such as easy implementation through character counts and the incorporation of overlap to ensure uninterrupted thoughts. Nonetheless, it does have limitations. The absence of precise control over context size, the potential for cutting words or sentences midway, and the disregard for semantic structure pose challenges. Consequently, when selecting a chunking method, it is crucial to consider the specific requirements of the task at hand, ensuring the chosen approach aligns with the desired outcomes. Here is a simple implementation.

from langchain.text_splitter import CharacterTextSplitter
text = """ Consider the source of your content and the diversity of data types.
Are you dealing with text from websites, databases, or user-generated content? 
Understanding the data source can inform your indexing strategy."""
text_splitter = CharacterTextSplitter(
    separator = "\n\n",
    chunk_size = 256,
    chunk_overlap  = 20 
)
docs = text_splitter.create_documents([text])

Output:

[Document(page_content='Consider the source of your content and the diversity of data types.\nAre you dealing with text from websites, databases, or user-generated content? \nUnderstanding the data source can inform your indexing strategy.')]

“Content-aware” Chunking

These methods are designed to harness the characteristics of the content being chunked and to apply more advanced chunking techniques.

Sentence Splitting

Just as we discussed earlier, there exists a multitude of models that excel in embedding content at the sentence level. Hence, it becomes pertinent to employ sentence chunking as a means to harness their capabilities. Fortunately, the realm of sentence chunking offers a rich array of approaches and tools, each possessing its own unique methodology.

Naive Splitting

Employing periods (“.”) and new lines as delimiters for sentence splitting represents the naivest approach. While this method may be fast and simple, it fails to consider all edge cases and poses challenges when dealing with text of varying structural complexity. On the positive side, this approach respects natural linguistic boundaries, ensuring that words, sentences, and thoughts are not severed within the chunks. It also strives to preserve the semantic integrity of information within each chunk. However, it does not guarantee perfect semantic consistency within the chunks, especially for larger structural units. Additionally, the lack of control over chunk size results in significant variations in chunk sizes derived from a given document. These pros and cons should be weighed carefully when deciding whether to adopt the naivest approach to sentence splitting.

NLTK

The Natural Language Toolkit (NLTK) stands as a popular Python library, specifically crafted for the manipulation of human language data. Its robust set of functionalities includes a sentence tokenizer, an essential tool for breaking text into meaningful sentences, thus facilitating the creation of coherent chunks. NLTK offers remarkable flexibility in chunking, empowering users to construct patterns using regular expressions or preset grammar rules. Notably, noun phrase chunking revolves around nouns, exemplified by phrases like “A new laptop,” while verb phrase chunking centers around verbs, as witnessed in “Bought a new laptop.”

NLTK relies on parts-of-speech (POS) tags to group words, assigning chunk tags to these groups. To ensure non-overlapping chunks, each word can only appear in one chunk at a time. NLTK finds extensive utility across diverse natural language processing tasks. Chunking plays a pivotal role in named entity recognition, information extraction, text classification and sentiment analysis, dialogue systems, and text summarization. By breaking down sentences into meaningful phrases, NLTK facilitates structured information extraction and furnishes valuable features for downstream NLP tasks.

While NLTK boasts numerous advantages, including its comprehensive text processing libraries, user-friendly interface, extensive documentation, and active community support, it does possess certain limitations. NLTK’s performance may be slower compared to other NLP libraries, and its Python basis may hinder scalability for industrial text processing with big data. Furthermore, some of its statistical models, like POS taggers, may be outdated and less accurate than modern alternatives. NLTK’s development has experienced a slowdown in recent years, with fewer major updates, and it lacks certain advanced NLP capabilities, such as word embeddings and deep learning integration.

In summary, while NLTK remains a valuable resource for various NLP applications, it may not be the ideal choice for large-scale production-grade systems, as its models and features lag behind other state-of-the-art NLP libraries.

Here is an implementation:

from langchain.text_splitter import NLTKTextSplitter
text = """ The Lord of the Rings" is an epic high fantasy trilogy written by English philologist and university professor J. 
R. R. Tolkien. The story began as a sequel to Tolkien's 1937 fantasy novel The Hobbit, 
but eventually developed into a much larger work. Written in stages between 1937 and 1949,
with much of it being written during World War II, The Lord of the Rings is split into three volumes and one appendix, 
and was originally published in three parts. It details an immense struggle of good versus evil, arising from the Dark 
Lord Sauron's forging of the One Ring, which grants almost absolute power. The story begins in the Shire, 
a peaceful hobbit-land, and follows the hobbit Frodo Baggins' 
quest to destroy the One Ring in the fires of Mount Doom, with the help of a Fellowship of the Ring.
"""
text_splitter = NLTKTextSplitter(
    chunk_size = 150,
    chunk_overlap = 100
)
docs = text_splitter.create_documents([text])

Output:

[Document(page_content='The Lord of the Rings" is an epic high fantasy trilogy written by English philologist and university professor J. \nR. R. Tolkien.'),
 Document(page_content="The story began as a sequel to Tolkien's 1937 fantasy novel The Hobbit, \nbut eventually developed into a much larger work."),
 Document(page_content='Written in stages between 1937 and 1949,\nwith much of it being written during World War II, The Lord of the Rings is split into three volumes and one appendix, \nand was originally published in three parts.'),
 Document(page_content="It details an immense struggle of good versus evil, arising from the Dark \nLord Sauron's forging of the One Ring, which grants almost absolute power."),
 Document(page_content="The story begins in the Shire, \na peaceful hobbit-land, and follows the hobbit Frodo Baggins' \nquest to destroy the One Ring in the fires of Mount Doom, with the help of a Fellowship.

spaCy

Within the realm of NLP, spaCy stands as a powerful knight, armed with an array of sophisticated tools. Picture this: spaCy, with its sentence segmentation feature, deftly slicing through text, preserving the essence of each sentence like a master swordsman. It doesn’t stop there. With its built-in syntactic chunking capabilities, spaCy weaves intricate patterns over its dependency parse tree, extracting meaningful chunks of information. This efficiency surpasses other libraries, making spaCy the knight with the sharpest sword.

These chunks serve as the building blocks for various NLP tasks, enhancing named entity recognition, relation extraction, text summarization, and sentiment analysis. They also boost information retrieval, text classification, and keyword extraction. In essence, spaCy’s chunking is like a blacksmith, forging the raw iron of text into the fine steel of meaningful phrases.

But what makes spaCy truly shine is its scalability, accuracy, and customizability. It’s like a well-crafted suit of armor, ready to take on large-scale NLP challenges. Its clean and intuitive API is the shield that guards against complexity, while its excellent documentation and active community serve as loyal allies in your quest for knowledge. In the grand tournament of real-world applications, spaCy proves to be a versatile, well-supported, and speed-optimized champion.

Here is a simple implementation:

from langchain.text_splitter import SpacyTextSplitter
text = """ The Lord of the Rings" is an epic high fantasy trilogy written by English philologist and university professor J. R. R. Tolkien. The story began as a sequel to Tolkien's 1937 fantasy novel The Hobbit, but eventually developed into a much larger work. Written in stages between 1937 and 1949,with much of it being written during World War II, The Lord of the Rings is split into three volumes and one appendix, and was originally published in three parts. It details an immense struggle of good versus evil, arising from the Dark Lord Sauron's forging of the One Ring, which grants almost absolute power. The story begins in the Shire, a peaceful hobbit-land, and follows the hobbit Frodo Baggins' quest to destroy the One Ring in the fires of Mount Doom, with the help of a Fellowship of the Ring."""

text_splitter = SpacyTextSplitter(
    chunk_size = 200,
    chunk_overlap = 100
)
docs = text_splitter.create_documents([text])

Output:

[Document(page_content='The Lord of the Rings" is an epic high fantasy trilogy written by English philologist and university professor J. \nR. R. Tolkien.'),
 Document(page_content="The story began as a sequel to Tolkien's 1937 fantasy novel The Hobbit, \nbut eventually developed into a much larger work."),
 Document(page_content='Written in stages between 1937 and 1949,\nwith much of it being written during World War II, The Lord of the Rings is split into three volumes and one appendix, \nand was originally published in three parts.'),
 Document(page_content="It details an immense struggle of good versus evil, arising from the Dark \nLord Sauron's forging of the One Ring, which grants almost absolute power."),
 Document(page_content="The story begins in the Shire, \na peaceful hobbit-land, and follows the hobbit Frodo Baggins' \nquest to destroy the One Ring in the fires of Mount Doom, with the help of a Fellowship of the Ring."),

Recursive Character Text Splitter

Recursive Character Text Splitter as a skilled artisan, meticulously carving a large block of text into smaller, manageable chunks. This tool, armed with a set of characters [“\n\n”, “\n”, ” “, “”], slices the text based on a specified chunk size. If a chunk is still too large, it deftly moves to the next character, repeating the process until the chunks are of the desired size.

This recursive text splitting is akin to a master sculptor, intelligently chiseling text into smaller units for various NLP tasks. It aids in tokenization, normalization, feature extraction, and parallelization, transforming messy text into clean, atomic units. It’s like taking a raw block of marble and sculpting it into a beautiful statue.

However, every tool has its strengths and weaknesses. The Recursive Character Text Splitter shines in its flexibility, customizability, and efficiency. It’s like a versatile chisel, able to carve any language with the right rules. Yet, without well-designed rulesets, the output can be brittle and lack coherence. It’s a reminder that even the most skilled artisan needs the right blueprint to create a masterpiece.

Here is a simple implementation of Recursive character text splitter:

from langchain.text_splitter import RecursiveCharacterTextSplitter
text = """ The Lord of the Rings" is an epic high fantasy trilogy written by English philologist and university professor J. 
R. R. Tolkien. The story began as a sequel to Tolkien's 1937 fantasy novel The Hobbit, 
but eventually developed into a much larger work. Written in stages between 1937 and 1949,
with much of it being written during World War II, The Lord of the Rings is split into three volumes and one appendix, 
and was originally published in three parts. It details an immense struggle of good versus evil, arising from the Dark 
Lord Sauron's forging of the One Ring, which grants almost absolute power. The story begins in the Shire, 
a peaceful hobbit-land, and follows the hobbit Frodo Baggins' 
quest to destroy the One Ring in the fires of Mount Doom, with the help of a Fellowship of the Ring.
The Lord of the Rings is one of the best-selling novels ever written, with over 150 million copies sold. 
It has been translated into 38 languages, and has been adapted into several films, radio series, video games, 
and an opera. The novel is also widely considered one of the greatest works of fantasy literature, 
and has been praised for its complex characters, detailed world-building, and exploration 
of themes such as good versus evil, power, and corruption."""
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 250,
    chunk_overlap  = 100,
    length_function = len,
    separators=["\n\n", "\n", " ", ""])
docs = text_splitter.create_documents([text])

Output:

page_content='The Lord of the Rings" is an epic high fantasy trilogy written by English philologist and university professor J. \nR. R. Tolkien. The story began as a sequel to Tolkien\'s 1937 fantasy novel The Hobbit,'

Document(page_content="R. R. Tolkien. The story began as a sequel to Tolkien's 1937 fantasy novel The Hobbit, \nbut eventually developed into a much larger work. Written in stages between 1937 and 1949,")

The Role of Chunking in RAG Performance Optimization

Successful Implementation of Advanced Chunking

Future Trends in RAG Performance Optimization

Conclusion

In the grand tapestry of Natural Language Processing, chunking is the intricate threadwork that brings structure and meaning to the raw fabric of text. It’s the process that transforms a monolithic block of data into a mosaic of insightful pieces, each carrying a nugget of information that contributes to the larger narrative.

With tools like spaCy and Recursive Character Text Splitter, we have the power to carve out these chunks with precision and efficiency. They are our chisels and hammers in the vast quarry of text data, helping us sculpt our raw material into meaningful insights. However, as with any tool, the artistry lies in the hands of the craftsman. The quality of our output depends on the rules we define, the parameters we set, and the context we consider. It’s a reminder that while our tools are powerful, they are but extensions of our intellect and creativity.

So, as we continue our journey in the realm of NLP, let’s appreciate the art of chunking. It’s the process that helps us see the forest for the trees, enabling us to extract value from the vastness of text data. After all, in the world of NLP, every chunk matters!

alagappan-ramanathan
About the Author
Senior Data Scientist with over 5 years of experience, specializing in AutoML, NLP, NLG, Computer Vision, Large Language Models (LLMs), and Gen AI. Recognized for implementing multiple data science solutions to drive innovation. Proven leadership in steering data science initiatives across Pharma, Finance, and Retail sectors, utilizing advanced techniques for strategic insights. Proficient in cloud platforms like AWS and Azure, ensuring seamless project deployments. Demonstrated ability to leverage the power of LLMs for comprehensive and impactful data science solutions. Committed to pushing the boundaries of innovation through a holistic approach that integrates both proprietary and open-source technologies.
Alagappan RamanathanSr. Data Scientist – Decision Intelligence | USEReady
Rahul S
About the Author
A Senior Data Scientist with over 8 years of professional experience, including more than 5 years in Data Science with a robust background in data analytics techniques to inform strategic business decisions and develop solutions that significantly impact organizational success. Areas of expertise include Predictive Modelling, Natural Language Processing (NLP), Deep Learning, Generative AI, and Large Language Models (LLMs).
Rahul SSr. Data Scientist – Decision Intelligence | USEReady