Vectors in vector search are numerical representations (embeddings) of data, such as text, images, or any object, encoded in a multi-dimensional space. Each vector is a list of float values [0.4322, 0.45666, 0.50434, 0.23455, .... ], and these values represent key features or characteristics of the data.
Key Points about Vector Search:
-
Vector Embeddings: The core idea is to convert complex data (like a sentence or an image) into a vector of float values using techniques like word embeddings (e.g. Google's pre-trained BERT model, OPENAI's text-embedding-3-small model or freenopen-source models) for text or image embeddings (e.g., CNNs model , florentgbelidji/blip_image_embeddings model).
-
Similarity: The similarity between vectors is often calculated using distance metrics such as:
- Cosine Similarity: Measures the cosine of the angle between two vectors.
- Euclidean Distance: Measures the "straight line" distance between two points (vectors) in the multi-dimensional space.
The closer the vectors (i.e., the smaller the distance between them), the more similar they are. In a similarity search, we typically retrieve vectors (and the corresponding data) that are nearest to the query vector.
How it Works:
-
Data Embedding: The first step is to convert raw data (text, images, etc.) into vectors. For example, using a pre-trained OPENAI text-embeddings model like text-embedding-3-small for text embeddings:
- A sentence like "How is the weather?" might be transformed into a 1536-dimensional vector.
-
Storing Vectors: Once vectors are created, we store them in a vector database like pgvector in Postgres or search engine like Typesense, Elasticsearch with vector support.
-
Query Embedding: When we search for similar data, the query (such as a sentence or image) is also converted into a vector using the same embedding model.
-
Similarity Search: The search engine finds the most similar vectors to the query vector by calculating distances between vectors. Results are ranked by how close the vectors are to the query vector.
- The smaller the distance, the more similar the items are.
Example:
Let’s assume we have embedded sentences into vectors, and one of vectors represents the sentence, "The weather is sunny today." When we search for "Is it sunny outside?", the search engine will compare the query vector to stored vectors and return the one for "The weather is sunny today" because their vectors are close in the vector space.
This approach is much more powerful than traditional keyword search, as it can capture the semantic meaning of data and retrieve similar items based on their conceptual closeness rather than exact word matches.
Vector search is widely used in various applications such as:
- Text retrieval: Finding similar articles or documents based on content.
- Recommendation systems: Recommending products, movies, or songs based on user preferences.
- Image search: Finding visually similar images based on embeddings extracted from CNN models.
By using vector embeddings and calculating the distance between them, vector search enables advanced similarity searches that are more meaningful and efficient than simple keyword matching.
Real World Vector Search Example Using Typesense.
Typesense is open-source search engine created for instant search-as-you-type experiences and developer productivity. An alternatice to ElasticSearch, Algolia - too easy to use and nice community support. Typesense has ability to index embeddings generated by ML models, then do a nearest-neighbor search. One example we can illustrate today is using Semantic Search. Semantic search helps retrieve results that are conceptually related to a user's query.
Let's start by creating a person schema where we'll leverage vector search using semantic query.
{
"name": "person",
"fields": [
{"name": "id", "type": "string"},
{"name": "name", "type": "string"},
{"name": "age", "type": "int32"},
{"name": "description", "type": "string"},
{"name": "email", "type": "string"},
{
"name": "vector",
"type": "float[]",
"num_dim":1536,
"embed": {
"from": [
"name",
"age",
"description",
"email"
],
"model_config": {
"model_name": "openai/text-embedding-3-small",
"api_key": "YOUR_OPENAI_APIKEY"
}
}
}
]
}
In above person schema, we've created a reserved name field vector with type float because as mentioned all the values stored are list of float values. We are using OPENAI text-embedding model called openai/text-embedding-3-small that accepts 8k+ inputs. You can read more about OPENAI available models here
Let's add some documents using Typesense Python Client:
# Set up Typesense client
client = typesense.Client({
'nodes': [{
'host': 'localhost', # Typesense server is running on localhost
'port': '8108',
'protocol': 'http'
}],
'api_key': 'TYPESENSE_APIKEY', # Your Typesense API Key
'connection_timeout_seconds': 2
})
# Person data
person_data = {
"id": "1",
"name": "John Doe",
"age": 32,
"profession": "software engineer",
"description": "John Doe is a software engineer with 10 years of experience in AI.",
"email": "john@example.com",
"embedding": generate_embedding("John Doe is a software engineer with 10 years of experience in AI.") # Generated embedding
}
# Insert person data into Typesense
response = client.collections['persons'].documents.create(person_data)
print(response)
Above, we indexed the person data into the persons collection along with the vector embeddings. The best thing about Typesense is - once schema is created with vector fields Typesense automatically uses each fields to generate vector values by using OPENAI API. The vector fields are only valid with string type and each vector values are the collection of string fields mentioned inside vector fields when creating schema and looks like:
"vector": [0.12, 0.34, 0.56, ..., 0.78]
The num_dim parameter in vector fields as mentioned in schema specifies the number of dimensions of the vector. It tells Typesense how many float values are present in each vector used for vector search in our case, 1536.
Let's perform a vector search, use the vector_query parameter in Typesense. This will allow us to search for the most similar persons based on their embeddings.
# Initialize the SentenceTransformer model
model = SentenceTransformer('text-embedding-3-small')
query_prompt="list all person who is software engineer aged 30 plus"
query_embedding = model.encode(query_prompt).tolist() # Convert to list for JSON compatibility
vector_query = f'vectors:([{",".join(map(str, query_embedding))}], k:200)'
# Prepare search request
search_parameters = {
"searches": [
{
"collection": "person",
"q": "*",
"exclude_fields": "vectors",
"page": 1,
"per_page": 100,
"vector_query": vector_query
}
]
}
common_params = {"filter_by":""}
# Make the search request
results= client.multi_search.perform({'searches': search_parameters["searches"]},common_params)
Summary of Workflow:
- Generate embeddings using OpenAI’s text-embedding-ada-002 model for each person.
- Define a schema in Typesense with a vector field (embedding).
- Create a persons collection in Typesense.
- Index the person data with the vector embeddings.
- Perform vector searches by comparing query embeddings to stored embeddings.
By doing this, you’ll be able to perform similarity searches based on the vector representation of person descriptions, enabling advanced semantic search capabilities.
Attached is a quick demo where I’ve showcased the powerful integration of Typesense’s vector search with a conversational UI built using ReactJS. In this video, you'll see how users can chat with an AI-powered interface to retrieve relevant results from a person collection stored in Typesense. By combining OpenAI’s text embeddings with Typesense’s fast and precise vector search, the system enhances user interactions, delivering personalized, context-aware search results in real-time.
Whether you're building search systems for e-commerce, HR, or support chatbots, this demo showcases how conversational AI and vector search can elevate how users interact with your data!
Thank you for reading. You're awesome!