2. VectorForge — C++ Vector Search Engin...
Audio version created with Paper2Audio.
Audio by Paper2Audio
2. VectorForge — C++ Vector Search Engine / Vector Database Prototype
Interview answer
“VectorForge is probably my most systems-oriented project.
It's a lightweight vector search engine that I built primarily in C++ to understand how vector databases and approximate nearest-neighbor search work internally.
The motivation behind the project came from working with modern A.I applications.
Today, rag systems, semantic search and recommendation systems commonly use vector databases. It's very easy to use an existing solution such as faiss, Qdrant or another vector database through an A.P.I, but I wanted to understand what actually happens internally when we search millions of high-dimensional vectors.
So instead of simply using an existing vector database, I implemented the core search algorithms myself.
The project supports three main search approaches: Brute Force, K.D-Tree and H.N.S.W.
It also supports similarity and distance metrics such as cosine similarity, Euclidean distance and Manhattan distance.
Let me first explain what is being searched.
An embedding is essentially a high-dimensional vector representation of data.
For example, a sentence can be converted by an embedding model into hundreds of numerical values. Semantically similar sentences should ideally produce vectors that are relatively close to each other in that vector space.
So if I have thousands of documents converted into embeddings and the user provides a query, I can convert the query into an embedding and search for the document vectors closest to it.
The simplest approach I implemented is Brute Force search.
In Brute Force, when a query vector comes in, I calculate its similarity or distance against every vector in the database.
If there are N vectors, that's approximately O(N) comparisons per query.
The advantage is that it is exact. Assuming the distance calculation is correct, I can find the actual nearest neighbors.
So Brute Force is extremely useful as a baseline.
I can compare the results from approximate algorithms against the exact results from Brute Force and evaluate the accuracy/performance trade-off.
The second structure I explored was the K.D-Tree.
A K.D-Tree recursively partitions multidimensional space.
For relatively low-dimensional data, this allows us to eliminate parts of the search space instead of comparing the query against every point.
However, K.D-Tree's have an important limitation for vector databases.
Modern embeddings can have hundreds or thousands of dimensions.
As dimensionality increases, K.D-Tree pruning becomes much less effective. This is related to the curse of dimensionality.
That's one reason modern vector search systems often use approximate nearest-neighbor algorithms instead.
The third and most important algorithm I implemented was H.N.S.W—Hierarchical Navigable Small World.
H.N.S.W is graph-based.
Each vector becomes a node in a graph and is connected to nearby vectors.
The graph has multiple layers.
Upper layers are sparse and allow the search algorithm to make large jumps across the vector space. Lower layers contain more nodes and provide increasingly fine-grained navigation.
When searching, I start from an entry point at one of the upper layers.
I compare the query vector with neighboring nodes and greedily move toward a node that is closer to the query.
Then I descend through the hierarchy.
At the bottom layer, the algorithm performs a broader candidate search and returns the closest vectors found.
The major advantage is that I don't need to compare against every stored vector.
The trade-off is that H.N.S.W performs approximate nearest-neighbor search.
It can occasionally miss the mathematically closest vector.
Parameters such as efSearch allow us to control that trade-off. Increasing the number of candidates explored generally improves recall but also increases computation and latency.
Implementing H.N.S.W was the hardest part of the project.
It wasn't simply implementing one search function.
I had to understand hierarchical graph construction, entry points, candidate priority queues, result queues, node connections, insertion and deletion, and how the graph index remains synchronized with the underlying vector storage.
That gave me a much better understanding of why production vector databases are significantly more complicated than just calculating cosine similarity.”
Your project implements Brute Force, K.D-Tree and H.N.S.W alongside multiple distance metrics, insertion/deletion, an in-memory vector store, benchmarking and an H.T.T.P layer.
Continue with the rag part
“After implementing vector search, I wanted to connect it to a real A.I use case, so I added a rag—Retrieval-Augmented Generation—pipeline.
The flow starts with a document.
I divide the document into smaller chunks.
Each chunk is converted into an embedding using Ollama with the nomic-embed-text embedding model.
Those embeddings are then inserted into VectorForge along with the associated document information.
When the user asks a question, I convert the question into an embedding using the same embedding model.
VectorForge performs nearest-neighbor search and retrieves the top-k chunks that are most semantically similar to the question.
Those retrieved chunks are then used as context for the language model.
Conceptually the pipeline is:
Document to Chunk to Embed to Index to User Question to Query Embedding to Vector Search to Top-K Chunks to L.L.M Context to Answer
This is the basic principle behind rag.
Instead of asking the language model to answer entirely from its training knowledge, I first retrieve information relevant to the question and provide that information as context.
That can make the response more grounded in the provided documents.”
The rag flow in your project follows document chunking to embeddings to vector storage to query embedding to top-k retrieval to L.L.M context generation.
Explain storage honestly
“For storage, the current implementation uses an in-memory structure rather than a production persistent database.
I maintain the vectors and associated information in C++ data structures and maintain the corresponding search indexes separately.
That means there is an important limitation: if the application restarts, the in-memory data isn't automatically durable.
I made that choice intentionally because my main goal was understanding indexing and search algorithms rather than implementing an entire distributed storage engine.
If I wanted to make VectorForge production-ready, I would need persistent vector and metadata storage, index snapshots or index reconstruction, replication, sharding, authentication, monitoring, fault tolerance and recovery mechanisms.”
Your current VectorForge uses an in-memory unordered map-based store and separate indexes rather than an external persistent database.
Why C++?
“I specifically chose C++ because this project is focused on performance-sensitive data structures and algorithms.
C++ gave me much more direct control over memory, data structures and performance than I would get from implementing the core engine entirely in a high-level language.
It also forced me to think carefully about object lifetimes, references, memory usage, synchronization and copying.
For exposing the engine to other applications, I added H.T.T.P A.P.I's using cpp-httplib.
I also used mutex-based synchronization where shared structures could be accessed concurrently.
Overall, VectorForge taught me algorithmic trade-offs, memory and performance considerations, concurrency, H.T.T.P A.P.I's and how modern semantic search and rag systems work internally.”
Your preparation likewise identifies C++ as useful for the performance-critical search/indexing core.
3. Packet Analyzer / D.P.I Engine — Network Traffic Inspection System
Interview answer
“My third project is a Packet Analyzer or Deep Packet Inspection Engine, which I implemented in C++.
This project is more focused on computer networking, systems programming and multithreading.
The basic objective was to understand how network traffic can be captured, inspected, classified and filtered based on information available inside packets and network flows.
A traditional packet analyzer can inspect information such as source I.P, destination I.P, ports and protocols.
I wanted to go a little further and identify application-level information where possible.
For example, with H.T.T.P traffic, the request can contain a Host header.
By parsing that information, the engine can determine which domain the client is trying to access.
H.T.T.P.S is more complicated because the actual H.T.T.P payload is encrypted using T.L.S.
However, during the T.L.S handshake, the client can include information called S.N.I—Server Name Indication—inside the ClientHello message.
S.N.I historically allows the server to determine which hostname the client is requesting so the server can present the appropriate certificate when multiple domains are hosted on the same I.P address.
My engine parses this information where it is visible and uses it for traffic classification.
So rather than only saying:
source I.P to destination I.P
I can potentially classify a connection based on the requested domain or application.”
Your D.P.I project is designed to inspect/classify H.T.T.P and T.L.S traffic using information such as H.T.T.P Host and T.L.S S.N.I and apply rule-based filtering.
Explain flow tracking
“Another important concept in the project is flow tracking.
Packets individually don't always give enough information about a connection.
So I identify network flows using the five-tuple:
Source I.P, Destination I.P, Source Port, Destination Port, Protocol
Packets belonging to the same connection can therefore be associated with the same flow.
This is useful because application classification or filtering may require maintaining state across multiple packets rather than treating every packet independently.
The engine can inspect traffic, associate packets with flows, extract application-level information where possible and then apply rule-based decisions.”
Explain multithreading
“I also wanted the analyzer to handle packet processing concurrently, so I used a multithreaded architecture.
A useful way to think about it is as a producer-consumer architecture.
The producer side is responsible for receiving or reading packets and putting work into a queue.
Worker or consumer threads take packets from the queue and perform processing such as parsing headers, tracking flows, classifying traffic and applying filtering rules.
This separation is useful because packet arrival and packet processing don't necessarily happen at exactly the same rate.
If processing every packet directly inside the capture path takes too long, packet ingestion could become a bottleneck.
Using worker threads allows multiple packets or flows to be processed concurrently.”
Your project preparation describes this producer-consumer design as packet readers feeding thread-safe queues that are processed by worker threads.
Thread safety
“Once I introduced multiple threads, I also had to think about thread safety.
If multiple worker threads access the same queue or shared flow state at the same time, race conditions can occur.
For shared queues, synchronization mechanisms such as mutexes protect the critical sections.
Condition variables can also be used so consumer threads don't continuously busy-wait when no packets are available.
This project therefore connected networking concepts with operating-system concepts such as threads, synchronization, mutexes, condition variables and race conditions.”
If interviewer asks: “How can you inspect H.T.T.P.S if it's encrypted?”
This is a likely follow-up.
Answer:
“I don't decrypt the H.T.T.P.S application payload.
H.T.T.P.S uses T.L.S, so after the T.L.S session is established, application data is encrypted.
However, some information needed to establish the T.L.S connection has traditionally been visible during the handshake.
For example, the ClientHello can contain an S.N.I extension identifying the requested hostname.
The analyzer can inspect that metadata without decrypting the actual H.T.T.P payload.
So I would be careful not to claim that my D.P.I engine reads encrypted H.T.T.P.S content. It classifies traffic using metadata that is available to it.”
That distinction is important and matches the scope of your project.
How the three projects connect
If the interviewer asks:
“Your three projects are very different. Why did you choose them?”
This is an excellent opportunity to connect them.
Answer:
“They look different at first, but each project helped me explore a different layer of software engineering.
ExamNotesAI is mainly an application-layer project. It taught me full-stack development, rest A.P.I's, authentication, databases, external A.P.I integration, payments and error handling.
VectorForge goes deeper into algorithms and systems. It helped me understand search algorithms, high-dimensional data, C++ performance, memory, concurrency and how vector databases and rag work internally.
And the Packet Analyzer focuses more on networking and low-level systems. It helped me understand packets, TCP/I.P, H.T.T.P, T.L.S, flow tracking and multithreaded processing.
So together, the projects gave me exposure to different layers.
With ExamNotesAI, I learned how to build an application.
With VectorForge, I learned more about how a data/search system works internally.
And with Packet Analyzer, I learned how network communication works underneath applications.
I think that combination is particularly relevant to an Application Engineer role because troubleshooting a real production application often requires understanding more than just application code. The problem might be in an A.P.I, database, application logic, external dependency, network or underlying system.”
Your 3-project mental map for tomorrow
Don't memorize these explanations word-for-word. Memorize the story of each project:
ExamNotesAI:
Problem to React to Express to Auth to Credits to Gemini to Structured jay-sun to MongoDB to Stripe to P.D.F to Security to Scaling
VectorForge:
Why vector D.B to Embeddings to Brute Force to K.D-Tree to H.N.S.W to Distance Metrics to C++ to Ollama to rag to Concurrency to Persistence limitation to Scaling
Packet Analyzer:
Packets to Protocol parsing to H.T.T.P Host to T.L.S/S.N.I to Five-Tuple to Flow tracking to Classification to Rules to Producer/Consumer to Multithreading to Mutex to Performance
For I.D.F.C, also be ready for the interviewer to turn each project into a banking/system-design question. For example: ExamNotesAI to “What if payment is processed twice?”; VectorForge to “How would you persist and scale it?”; Packet Analyzer to “How does H.T.T.P.S/T.L.S work?” That is where your project explanation can quickly become a deeper technical round.