🪿 Register for November's , using Hono as an api framework, Neon Postgres as a database, Drizzle as a typesafe ORM, and Cloudflare Workers as the serverless deployment platform.
We'll build a small semantic search engine for Cloudflare's documentation, giving us a system that understands the meaning behind search queries, not just keyword matches.
🔗 He draws a comparison to colors. There's a difference between describing a color with a name, like
"blue", versus with an RGB valuergb(0, 0, 255). In this case, the RGB value is a vector of length three,(0, 0, 255).
If we wanted to mix some red into the named color
"blue"and make a new color that's just a little more purple, how would we do that?
Well, if all we have is the name of the color, there's not much we can do. We'd just invent a new color and give it a new name, like
"purpleish blue". With an RGB value, though, we can simply "add" some red:
rgb(20, 0 , 0) + rgb(0, 0, 255) = rgb(20, 0, 255)
Because we chose to represent our color with vectors of numbers, we can do math on it. We can change it around, mix it with other colors, and have an all around good time with it.
Embeddings are a way for us to do this kind of math on human language. Embeddings are vectors, like RGB values, except they're much larger.
How would you "do math on human language" though? Borrowing an example from the trusty Internet, let's say we have a vector for the word
"king", and a vector for the words"man"and"woman".
If we subtract the vector for
"man"from the vector for"king", then add the vector for the word"woman". What would you expect we get?
Wild enough, we would get a vector very very close to the one for the word"queen".
Pretty neat, huh?
Vector Search
Searching across vectors usually refers to looking for vectors that are similar to one another.
In this case, we think of similarity in terms of distance. Two vectors that are close to one another are similar. Two vectors that are far apart are different.
So, in a database that stores vectors, we can calculate the distance between an input vector, and all vectors in the database, and return only the ones that are most similar.
In this post, you will see a reference to "cosine similarity", which is a way to calculate the distance between two vectors. So, don't get freaked if we start talking about cosines.
Basically, instead of looking for exact matches or keyword matches for a user's query, we look for "semantically similar matches" based off of cosine distance.
How Do We Start?
To perform semantic search, we need:
- a database that supports vector embeddings
- a way to vectorize text
- a way to search for similar vectors in the database
To be entirely frank, the hardest part of building semantic search is knowing how to parse and split up your target documents text into meaningful chunks.
I spent most of my time on this project just pulling down, compiling, and chunking the Cloudflare documentation. After that, the search part was easy-peasy.
I will gloss over the tedious parts of this below, but I've provided a link to the script that processes the documentation, for anyone who is interested.
That said, let's go over the stack and database models we'll be using for the actual searching part.
The Stack
We want to expose a simple API for users to search the Cloudflare documentation. Then we want some tools for storing the documents and their embeddings, as well as querying them.
Here's the stack we'll be using for all of this:
Hono: A lightweight web framework for building typesafe APIs
Neon Postgres: Serverless postgres database for storing documents and vector embeddings
OpenAI: To vectorize documentation content and user queries
Drizzle ORM: For constructing type-safe database operations
Cloudflare Workers: To host the API on a serverless compute platform
Setting up the Database
First, we define a schema using Drizzle ORM.
When we craft our database models, we have to think of what kind of search results we want to return.
This leads us to the idea of "chunking", which is the process of splitting up the text into smaller chunks.
The logic is: We don't want to match a user's query to entire documents, because that would return a lot of irrelevant results.
Instead, we should split up each documentation page into smaller chunks, and match the user's query to the most semantically similar chunks.
Since we're working witha relational database, we can define a schema for the documents and chunks, where each document can have many chunks.
So, our Drizzle schema defines two main tables:
documents: Stores the original documentation pages
chunks: Stores content chunks with their vector embeddings
CODEexport const documents = pgTable("documents", {
id: uuid("id").defaultRandom().primaryKey(),
title: text("title").notNull(),
url: text("url"),
content: text("content"),
hash: text("hash").notNull()
});
export const chunks = pgTable("chunks", {
id: uuid("id").defaultRandom().primaryKey(),
documentId: uuid("document_id")
.references(() => documents.id)
.notNull(),
chunkNumber: integer("chunk_number").notNull(),
text: text("text").notNull(),
embedding: vector("embedding", { dimensions: 1536 }),
metadata: jsonb("metadata").$type<Array<string>>(),
hash: text("hash").notNull()
});
Once we define a schema, we can create the tables in our database.
If you're following along on GitHub, you can run the commands below to create the tables.
Under the hood, we use Drizzle to generate migration files and apply them to the database.
CODEpnpm db:generate
pnpm db:migrate
Now, with our database set up, we can move on to processing the documentation itself into vector embeddings.
Processing Documentation
The heart of our system is the document processing pipeline. It's a bit of a beast.
I'm going to move through this quickly, but you can see the full implementation in
And that's it! We've built a semantic search engine with the HONC stack.
The Magic of Vector Search
What makes this more powerful than regular text search? Again, vector embeddings capture semantic meaning. For example, a search for "how to handle errors in Workers" will find relevant results even if they don't contain those exact words.
Neon makes this simple, easy, and scalable by allowing efficient similarity searches over high-dimensional vectors out of the box.
However, that doesn't mean that vector search is the only tool for retrieval. Any robust system should consider the trade-offs of vector search vs. keyword search, and likely combine the two.
Deployment
🔗 and
Otherwise, don't forget to check out the HONC stack for more examples of building with Hono, Drizzle, Neon, and Cloudflare.
↗ Original-Artikel auf dev.to lesenVollständiger Original-BerichtAusführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
Ähnliche Beiträge
Auch interessante Nachrichten Retrieval Augmented Geese - Semantic Search with the HONC Stack
Thematisch verwandte Begriffe: Retrieval, Augmented, Geese, Semantic · 6 Treffer
Building Agentic RAG, Step by Step: From Static Retrieval to Reasoning Pipelines
Agentic Frameworks Summary
Getting the Most Out of Transformers in Elastic
REVSTEALER ramps up: analysis of up-and-coming infostealer
[webapps] Grav CMS 2.0.7 - RCE
Using LLMs and ESRE to find similar user sessions
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
SOCIAL SHARE CARD GENERATOR