Skip to content

Commit 74b3b4c

Browse files
Merge pull request #27 from Build5Nines/dev
v2.0.1
2 parents 7ccaf1d + 81ed891 commit 74b3b4c

7 files changed

Lines changed: 138 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## v2.0.0
8+
## 2.0.1 (2025-03-17)
9+
10+
Added:
11+
12+
- Expose internal vector array of `VectorTextItem` from `VectorTextResultItem.Vectors` property, to make vector array accessible for consuming code in cases where access is required. This is mostly for more flexible usage of the library.
13+
- Added Overlapping Window text chunking (`TextChunkingMethod.OverlappingWindow`) to `TextDataLoader` for enhanced document segmentation with overlapping content, improving metadata extraction and search result relevance.
14+
15+
Fixed:
16+
17+
- When using `Data.TextDataLoader` with `TextChunkingMethod.FixedLength` it was splitting on a space character which wouldn't work correctly with Chinese text characters. This is now fixed to work correctly with Chinese characters too.
18+
19+
## v2.0.0 (2025-02-23)
920

1021
Added:
1122

src/Build5Nines.SharpVector/Build5Nines.SharpVector.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<PackageId>Build5Nines.SharpVector</PackageId>
1010
<PackageProjectUrl>https://github.com/Build5Nines/SharpVector</PackageProjectUrl>
1111
<RepositoryUrl>https://github.com/Build5Nines/SharpVector</RepositoryUrl>
12-
<Version>2.0.0</Version>
12+
<Version>2.0.1</Version>
1313
<Description>Lightweight In-memory Vector Database to embed in any .NET Applications</Description>
1414
<Copyright>Copyright (c) 2025 Build5Nines LLC</Copyright>
1515
<PackageReadmeFile>README.md</PackageReadmeFile>

src/Build5Nines.SharpVector/Data/TextChunkingMethod.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,9 @@ public enum TextChunkingMethod
1313
/// <summary>
1414
/// Split the text into fixed length chunks
1515
/// </summary>
16-
FixedLength
16+
FixedLength,
17+
/// <summary>
18+
/// Split the text into overlapping windows
19+
/// </summary>
20+
OverlappingWindow
1721
}

src/Build5Nines.SharpVector/Data/TextChunkingOptions.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public TextChunkingOptions()
99
#pragma warning disable CS8603 // Possible null reference return.
1010
RetrieveMetadata = (chunk) => default;
1111
#pragma warning restore CS8603 // Possible null reference return.
12+
OverlapSize = 50;
1213
}
1314

1415
/// <summary>
@@ -17,13 +18,18 @@ public TextChunkingOptions()
1718
public TextChunkingMethod Method { get; set; }
1819

1920
/// <summary>
20-
/// The size of each chunk of text. Default is 100.
21-
/// Used only for FixedLength method
21+
/// The length in tokens (aka "words") of each chunk of text. Default is 100.
22+
/// Only used by TextChunkingMethod.FixedLength and TextChunkingMethod.OverlappingWindow.
2223
/// </summary>
23-
public int ChunkSize { get; set; }
24+
public int ChunkSize { get; set; }
2425

2526
/// <summary>
2627
/// Lambda function to retrieve custom metadata for each chunk
2728
/// </summary>
2829
public Func<string, TMetadata> RetrieveMetadata { get; set; }
30+
31+
/// <summary>
32+
/// The number of words to overlap text chunks when using using TextChunkingMethod.OverlappingWindow. Default is 50.
33+
/// </summary>
34+
public int OverlapSize { get; set; }
2935
}

src/Build5Nines.SharpVector/Data/TextDataLoader.cs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ namespace Build5Nines.SharpVector.Data;
22

33
using System.ComponentModel.DataAnnotations;
44
using System.Text.RegularExpressions;
5+
using Build5Nines.SharpVector.Preprocessing;
56

67
public class TextDataLoader<TId, TMetadata>
78
where TId : notnull
@@ -12,6 +13,8 @@ public TextDataLoader(IVectorDatabase<TId, TMetadata> vectorDatabase)
1213
VectorDatabase = vectorDatabase;
1314
}
1415

16+
const string _space = " ";
17+
1518
public IVectorDatabase<TId, TMetadata> VectorDatabase { get; private set; }
1619

1720
public IEnumerable<TId> AddDocument(string document, TextChunkingOptions<TMetadata> chunkingOptions)
@@ -41,6 +44,8 @@ protected List<string> ChunkText(string text, TextChunkingOptions<TMetadata> chu
4144
return SplitIntoSentences(text);
4245
case TextChunkingMethod.FixedLength:
4346
return SplitIntoChunks(text, chunkingOptions.ChunkSize);
47+
case TextChunkingMethod.OverlappingWindow:
48+
return SplitIntoOverlappingWindows(text, chunkingOptions.ChunkSize, chunkingOptions.OverlapSize);
4449
default:
4550
throw new ArgumentException("Invalid chunking method");
4651
}
@@ -58,18 +63,67 @@ protected static List<string> SplitIntoSentences(string text)
5863

5964
protected static List<string> SplitIntoChunks(string text, int chunkSize)
6065
{
61-
var words = text.Split(' ');
66+
var words = SplitIntoTokens(text);
6267
var chunks = new List<string>();
6368

64-
const string space = " ";
6569
for (int i = 0; i < words.Length; i += chunkSize)
6670
{
67-
chunks.Add(string.Join(space, words.Skip(i).Take(chunkSize)));
71+
chunks.Add(JoinTokens(words.Skip(i).Take(chunkSize)));
6872
}
6973

7074
return chunks;
7175
}
7276

77+
protected static List<string> SplitIntoOverlappingWindows(string text, int chunkSize, int overlap)
78+
{
79+
var tokens = SplitIntoTokens(text);
80+
var chunks = new List<string>();
81+
82+
if (overlap >= chunkSize)
83+
throw new ArgumentException("Overlap must be smaller than chunk size");
84+
85+
// Calculate the step size
86+
int step = chunkSize - overlap;
87+
int tokenLength = tokens.Length;
88+
for (int i = 0; i < tokenLength; i += step)
89+
{
90+
var chunk = JoinTokens(tokens.Skip(i).Take(chunkSize));
91+
if (!string.IsNullOrWhiteSpace(chunk))
92+
chunks.Add(chunk);
93+
94+
if (i + chunkSize >= tokenLength)
95+
break;
96+
}
97+
return chunks;
98+
}
99+
100+
private static string JoinTokens(IEnumerable<string> tokens)
101+
{
102+
if (tokens == null) return string.Empty;
103+
104+
var fullText = new System.Text.StringBuilder();
105+
foreach (var token in tokens)
106+
{
107+
if (IsChinese(token))
108+
fullText.Append(token);
109+
else
110+
fullText.Append(_space + token);
111+
}
112+
return fullText.ToString().Trim();
113+
}
114+
115+
private static bool IsChinese(string token)
116+
{
117+
// Checks if the token consists entirely of Chinese (CJK Unified Ideograph) characters.
118+
return System.Text.RegularExpressions.Regex.IsMatch(token, @"^\p{IsCJKUnifiedIdeographs}+$");
119+
}
120+
121+
protected static string[] SplitIntoTokens(string text)
122+
{
123+
var processor = new BasicTextPreprocessor();
124+
return processor.TokenizeAndPreprocess(text).ToArray();
125+
}
126+
73127
public async Task<IEnumerable<TId>> AddDocumentAsync(string document, TextChunkingOptions<TMetadata> chunkingOptions)
74128
{
75129
if (chunkingOptions.RetrieveMetadata == null)

src/Build5Nines.SharpVector/VectorTextResultItem.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Collections.Immutable;
2+
13
namespace Build5Nines.SharpVector;
24

35
public interface IVectorTextResultItem<TDocument, TMetadata>
@@ -23,6 +25,9 @@ public VectorTextResultItem(IVectorTextItem<TDocument, TMetadata> item, float ve
2325

2426
public TDocument Text { get => _item.Text; }
2527
public TMetadata? Metadata { get => _item.Metadata; }
28+
29+
public ImmutableArray<float> Vectors { get => ImmutableArray.Create(_item.Vector); }
30+
2631
public float VectorComparison { get; private set; }
2732
}
2833

src/SharpVectorTest/Data/TextDataLoaderTests.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,53 @@ public void TextDataLoader_Paragraphs_01()
4848
Assert.AreEqual("{ chuckSize: \"133\" }", results.Texts.First().Metadata);
4949
Assert.AreEqual(0.3396831452846527, results.Texts.First().VectorComparison);
5050
}
51+
52+
[TestMethod]
53+
public void TextDataLoader_OverlappingWindow_01()
54+
{
55+
var vdb = new BasicMemoryVectorDatabase();
56+
57+
// // Load Vector Database with some sample text
58+
var document = "The Lion King is a 1994 Disney animated film about a young lion cub named Simba who is the heir to the throne of an African savanna. \n\n" +
59+
"Aladdin is a 2019 live-action Disney adaptation of the 1992 animated classic of the same name about a street urchin who finds a magic lamp and uses a genie's wishes to become a prince so he can marry Princess Jasmine. \n\n" +
60+
"The Little Mermaid is a 2023 live-action adaptation of Disney's 1989 animated film of the same name. The movie is about Ariel, the youngest of King Triton's daughters, who is fascinated by the human world and falls in love with Prince Eric. \n\n" +
61+
"Frozen is a 2013 Disney movie about a fearless optimist named Anna who sets off on a journey to find her sister Elsa, whose icy powers have trapped their kingdom in eternal winter. \n\n" +
62+
"Tangled is a 2010 Disney animated comedy adventure film based on the story of Rapunzel. The movie is about a long-lost princess with magical blonde hair who has been locked in a tower her entire life by Gothel, who wants to use Rapunzel's powers for herself. \n\n" +
63+
"Wreck-It Ralph is a 2012 Disney animated film about Ralph, a character who plays the bad guy in the arcade game Fix-It Felix Jr. for 30 years. Ralph is a muscular, 9-foot-tall character with spiky auburn hair, a pink nose, and large hands and feet. He wears burgundy overalls with a broken strap, a plaid shirt with ripped sleeves, and a teal undershirt. \n\n" +
64+
"Iron Man (2008) is a Marvel Studios action, adventure, and sci-fi movie about Tony Stark (Robert Downey Jr.), a billionaire inventor and weapons developer who is kidnapped by terrorists and forced to build a weapon. Instead, Tony uses his ingenuity to build a high-tech suit of armor and escape, becoming the superhero Iron Man. He then returns to the United States to refine the suit and use it to fight crime and terrorism. \n\n" +
65+
"Black Panther is a 2018 Marvel Studios movie about T'Challa, the heir to the isolated African nation of Wakanda, who returns home to take the throne after his father's death. However, T'Challa faces challenges from within his own country, including Killmonger, who wants to abandon Wakanda's isolationist policies and start a global revolution. T'Challa must team up with C.I.A. agent Everett K. Ross and the Dora Milaje, Wakanda's special forces, to prevent Wakanda from being drawn into a world war. \n\n" +
66+
"Black Panther: Wakanda Forever is a 2022 Marvel movie about the Wakandans fighting to protect their country from world powers after the death of King T'Challa. The movie is a sequel to the popular Black Panther and stars Chadwick Boseman as T'Challa, Letitia Wright as Shuri, Angela Bassett as Ramonda, and Tenoch Huerta Mejía as Namor. \n\n" +
67+
"The Incredible Hulk is a 2008 Marvel movie about scientist Bruce Banner (Edward Norton) who turns into a giant green monster called the Hulk when he's angry or frightened. After a gamma radiation accident, Banner is on the run from the military while searching for a cure for his condition. \n\n" +
68+
"Hackers is a 1995 American crime thriller film about a group of high school hackers who discover a criminal plot to use a computer virus to destroy five oil tankers. The film stars Jonny Lee Miller, Angelina Jolie, Jesse Bradford, Matthew Lillard, Laurence Mason, Renoly Santiago, Lorraine Bracco, and Fisher Stevens. Iain Softley directed the film, which was made during the mid-1990s when the internet was becoming popular. \n\n" +
69+
"WarGames is a 1983 American techno-thriller film about a high school computer hacker who accidentally accesses a top secret military supercomputer that controls the U.S. nuclear arsenal. The hacker, David Lightman (Matthew Broderick), starts a game of Global Thermonuclear War, triggering a false alarm that threatens to start World War III. David must convince the computer that he only wanted to play a game and not the real thing, with help from his girlfriend (Ally Sheedy) and a government official (Dabney Coleman) \n\n" +
70+
"Cars is a 2006 Pixar movie about a rookie race car named Lightning McQueen who gets stranded in a small town while on his way to an important race. McQueen accidentally damages the road in Radiator Springs, a forgotten town on Route 66, and is forced to repair it. While there, he meets Sally, Mater, Doc Hudson, and other characters who help him learn that there's more to life than fame and trophies. McQueen finds friendship and love in the town, and begins to reevaluate his priorities. The movie teaches McQueen the importance of caring for others, integrity, and that winning isn't everything. \n\n" +
71+
"The Incredibles is a 2004 Pixar animated action-adventure film about a family of superheroes who are forced to live a normal suburban life while hiding their powers. The movie is set in a retro-futuristic 1960s and has a runtime of 1 hour and 55 minutes. \n\n" +
72+
"Toy Story is a 1995 animated comedy film about the relationship between Woody, a cowboy doll, and Buzz Lightyear, an action figure. The film takes place in a world where toys come to life when humans are not present. Woody is the leader of the toys in Andy's room, including a Tyrannosaurus Rex and Mr. Potato Head. When Buzz becomes Andy's favorite toy, Woody becomes jealous and plots against him. When Andy's family moves, Woody and Buzz must escape the clutches of their neighbor, Sid Phillips, and reunite with Andy. \n\n" +
73+
"In Toy Story 2, Andy's toys are left to their own devices while he goes to Cowboy Camp, and Woody is kidnapped by a toy collector named Al McWhiggin. Buzz Lightyear and the other toys set out on a rescue mission to save Woody before he becomes a museum toy. \n\n" +
74+
"Iron Man 2 is a 2010 action-adventure fantasy film about Tony Stark (Robert Downey Jr.), a billionaire inventor and superhero who must deal with declining health, government pressure, and a vengeful enemy. \n\n" +
75+
"";
76+
77+
var loader = new TextDataLoader<int, string>(vdb);
78+
loader.AddDocument(document, new TextChunkingOptions<string>
79+
{
80+
Method = TextChunkingMethod.OverlappingWindow,
81+
ChunkSize = 5,
82+
OverlapSize = 2,
83+
RetrieveMetadata = (chunk) => {
84+
// add some basic metadata since this can't be null
85+
return "{ chuckSize: \"" + chunk.Length + "\" }";
86+
}
87+
});
88+
89+
var results = vdb.Search("Lion King", pageCount: 10, threshold: 0.3f);
90+
91+
var texts = results.Texts.ToArray();
92+
93+
Assert.AreEqual(5, results.Texts.Count());
94+
Assert.AreEqual("the lion king is a", texts[0].Text);
95+
Assert.AreEqual("{ chuckSize: \"18\" }", texts[0].Metadata);
96+
97+
Assert.AreEqual("death of king tchalla the", texts[1].Text);
98+
Assert.AreEqual("youngest of king tritons daughters", texts[2].Text);
99+
}
51100
}

0 commit comments

Comments
 (0)