Introduction to Semantic Search with Python and OpenAI API
Tags: ai, semanticsearch, openai, python
Published: 2024-05-01 17:13:39


**Semantic search** represents a significant leap over traditional keyword-based search methods. Instead of merely matching keywords or phrases, semantic search _comprehends_ the context and underlying meaning behind a query, providing more relevant and intelligent search results. This approach leverages advanced Natural Language Processing (NLP) techniques and is particularly useful in applications where understanding user intent and content relevance is crucial.

In this tutorial, we'll dive into the basics of implementing semantic search using Python :snake: and the OpenAI API. We'll focus on document embeddings to demonstrate how text can be converted into numerical vectors that machines can understand and process.

## Understanding Document Embeddings


![Embedding](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rfdsncvtnu280x6w41ck.png)



Document embeddings are like the secret sauce powering semantic search technologies, transforming how we interact with text-based information. They're not just about finding exact word matches; they dive into the deeper layers of meaning within documents to help systems understand relevance in context.

To grasp the concept of document embeddings, let's unpack the core elements that drive their functionality:

**Dimensionality**

Picture document embeddings like puzzle pieces scattered across a vast landscape, each representing a different facet of meaning. These embeddings live in high-dimensional spaces, often spanning hundreds of dimensions. Think of it like having hundreds of different lenses to view the same text, each revealing a unique angle. For example, **OpenAI's Ada model** crafts embeddings in an **over 1,000-dimensional space**. This multidimensional approach allows us to capture the richness and depth of textual content, capturing nuances that go beyond simple word matching.

**Vector Elements**

At the heart of every embedding vector are floating-point numbers – the building blocks of meaning. These numbers aren't just random; they're carefully crafted to encode the essence of the text. They capture everything from the words themselves to the grammar and syntax, weaving together a rich tapestry of meaning. **By translating language into numbers**, document embeddings make it easier for computers to understand and compare textual information, almost like speaking their language.

**Normalization**

Normalization is like the referee ensuring a fair game in the world of document embeddings. It's all about making sure that different embeddings play by the same rules. Through normalization, we standardize the length of embedding vectors, ensuring they're all on an even playing field. This consistency makes it easier to compare vectors using techniques like **[cosine similarity](https://en.wikipedia.org/wiki/Cosine_similarity)**, helping us measure how closely related different pieces of text are. By leveling the playing field, normalization helps semantic search algorithms find those subtle connections that might otherwise be missed.

## And now to the fun part: Step-by-Step implementation

How can we visualize all of these concepts and see them in action? :eyes:

Let's walk through a simple Python script to implement a basic semantic search using embeddings from the OpenAI API.

You’ll need:

- a valid OpenAI API Key
_Please be advised that use of the OpenAI API may require payment for access to certain features and services. Make sure to review and understand the terms and conditions associated with each plan before proceeding._

- an environment where you can run Python (can be locally or in platforms such as Google Colab)

**Step 1: Setting Up Your Environment**

First, ensure you have Python installed along with the requests and numpy libraries. You can install these packages using pip:

```python
pip install requests numpy
```
**Step 2: Authenticating with the OpenAI API**

Replace `'your-openai-api-key'` in the script with your actual API key.

**Step 3: Fetching Embeddings**

Here's how to define a function in Python to fetch embeddings from the OpenAI API:

```python
import requests
import numpy as np

api_key = 'your-openai-api-key'`

def get_embeddings(texts):
 headers = {
 'Authorization': f'Bearer {api_key}',
 'Content-Type': 'application/json',
 }
 data = {
 'input': texts,
 'model': "text-embedding-ada-002"
 }
 response = requests.post('https://api.openai.com/v1/embeddings', headers=headers, json=data)
 return np.array([item['embedding'] for item in response.json()['data']])
```

**Step 4: Implementing the Search Function**

The search function calculates cosine similarities between the query embedding and each document embedding, returning the most relevant document.

```python
def search(documents, query):
 document_embeddings = get_embeddings(documents)
 query_embedding = get_embeddings([query])[0]
 scores = np.dot(document_embeddings, query_embedding)
 return documents[np.argmax(scores)]
```

**Step 5: Running Your Semantic Search**

Define some sample documents and a query:

```python
documents = [
    "Dave Grohl likes to play drums.",
    "Artificial intelligence is reshaping industries and societies.",
    "The mitochondrion is known as the powerhouse of the cell.",
    "Mate is a very popular beverage in Argentina",
    "Czech Republic's population in 2022 is 10.67 million."
]

query = "What can I drink today?"
result = search(documents, query)
print("Search Result:", result)
```

In this example, as we asked _"What can I drink today?"_ likely the result would be **"Mate is a very popular beverage in Argentina"**. :mate:

## Conclusion

Semantic search is transforming how we interact with data. By understanding the deeper meaning of text, systems can provide more accurate and useful results. This tutorial introduces you to the basics of building a semantic search engine using Python and the OpenAI API, which you can extend to more complex and robust applications.
By using embeddings and calculating similarities, developers can create systems that are not only efficient but also capable of understanding the nuances of human language, making technologies more intuitive and user-friendly.