Skip to content

Commit 0bfc7c1

Browse files
committed
Adding self-query script for blog
Adding the code, readme, and requirements for the upcoming blog on self-querying retrievers
1 parent ced23e5 commit 0bfc7c1

File tree

3 files changed

+200
-0
lines changed

3 files changed

+200
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Self-querying retrieval with Elasticsearch
2+
3+
This script will show you how to ingest and create embeddings for documents which will then be used as part of a self-querying retriever
4+
5+
> **Tip:** To learn more about Elastic Cloud and how to use it, visit: [https://www.elastic.co/pt/cloud](https://www.elastic.co/pt/cloud)
6+
7+
## Prerequisites
8+
9+
- **Elasticsearch v8.16** (recommended): To support the latest semantic search features, this script in its current form utilizes Elastic Cloud but can be modified for self-managed
10+
- **Python 3.x**
11+
- **API Access to an LLM and embedding model**: This script requires an LLM for the retriever as well as an embedding model for creating vectors in our documents, the script assumes usage of Azure OpenAI but this can easily changed to another cloud based LLM or local one like Llama 3.
12+
- **Python Libraries**: Required libraries are listed in the `requirements.txt` file.
13+
14+
To install the dependencies, use the following command:
15+
16+
```bash
17+
pip install -r requirements.txt
18+
```
19+
20+
or run the following individual pip commands:
21+
22+
# Core LangChain library
23+
```bash
24+
pip install langchain
25+
```
26+
# OpenAI integration for LangChain (Azure OpenAI support)
27+
```bash
28+
pip install langchain-openai
29+
```
30+
# Elasticsearch integration for LangChain
31+
```bash
32+
pip install langchain-elasticsearch
33+
```
34+
# Elasticsearch Python client (required for ElasticsearchStore)
35+
```bash
36+
pip install elasticsearch
37+
```
38+
# Additional dependencies for embeddings and document handling
39+
```bash
40+
pip install langchain-core langchain-community
41+
```
42+
```bash
43+
pip install lark
44+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
langchain-openai>=0.0.2
2+
langchain-elasticsearch>=0.0.1
3+
elasticsearch>=8.0.0
4+
langchain-core>=0.1.0
5+
aiohttp>=3.8.0
6+
openai>=1.0.0
7+
typing-extensions>=4.5.0
8+
pydantic>=2.0.0
9+
tenacity>=8.2.0
10+
lark>=1.1.5
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from langchain_openai import AzureOpenAIEmbeddings, AzureChatOpenAI
2+
from langchain_elasticsearch import ElasticsearchStore
3+
from langchain.chains.query_constructor.base import AttributeInfo
4+
from langchain.retrievers.self_query.base import SelfQueryRetriever
5+
from langchain.docstore.document import Document
6+
import os
7+
8+
# --- Environment Configuration (Set these variables) ---
9+
os.environ["AZURE_OPENAI_API_KEY"] = "" # Replace with your actual key
10+
os.environ["AZURE_ENDPOINT"] = "" # Replace with your endpoint
11+
os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"] = "gpt-4" # For LLM
12+
os.environ["AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME"] = "text-embedding-ada-002" # For embeddings
13+
14+
ELASTIC_CLOUD_ID = "" #if using Elastic Cloud, your Cloud ID
15+
ELASTIC_USERNAME = "" # ES user, alternatively can be API key
16+
ELASTIC_PASSWORD = ""
17+
ELASTIC_INDEX_NAME = "yourElasticIndex" #replace with your index name, if no matching index is present one will be created
18+
19+
# --- Initialize LLM and Embeddings ---
20+
llm = AzureChatOpenAI(
21+
azure_endpoint=os.environ["AZURE_ENDPOINT"],
22+
deployment_name=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
23+
model_name="gpt-4",
24+
api_version="2024-02-15-preview"
25+
)
26+
27+
embeddings = AzureOpenAIEmbeddings(
28+
azure_endpoint=os.environ["AZURE_ENDPOINT"],
29+
model="text-embedding-ada-002"
30+
)
31+
32+
# --- Define Metadata Attributes ---
33+
metadata_field_info = [
34+
AttributeInfo(
35+
name="year",
36+
description="The year the movie was released",
37+
type="integer",
38+
),
39+
AttributeInfo(
40+
name="rating",
41+
description="The rating of the movie (out of 10)",
42+
type="float",
43+
),
44+
AttributeInfo(
45+
name="genre",
46+
description="The genre of the movie",
47+
type="string",
48+
),
49+
AttributeInfo(
50+
name="director",
51+
description="The director of the movie",
52+
type="string",
53+
),
54+
AttributeInfo(
55+
name="title",
56+
description="The title of the movie",
57+
type="string",
58+
)
59+
]
60+
61+
# --- Ingest the Documents ---
62+
docs = [
63+
Document(
64+
page_content="A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.",
65+
metadata={"year": 2010, "rating": 8.8, "genre": "science fiction", "title": "Inception"},
66+
),
67+
Document(
68+
page_content="When the menace known as the Joker emerges from the shadows, it causes Batman to question everything he stands for.",
69+
metadata={"year": 2008, "rating": 9.0, "genre": "action", "title": "The Dark Knight"},
70+
),
71+
Document(
72+
page_content="The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son.",
73+
metadata={"year": 1972, "rating": 9.2, "genre": "crime", "title": "The Godfather"},
74+
),
75+
Document(
76+
page_content="A young hobbit, Frodo, is tasked with destroying an ancient ring that holds the power to enslave the world.",
77+
metadata={"year": 2001, "rating": 8.8, "genre": "fantasy", "title": "The Lord of the Rings: The Fellowship of the Ring"},
78+
),
79+
Document(
80+
page_content="A cyborg assassin travels back in time to kill the mother of the future leader of the human resistance.",
81+
metadata={"year": 1984, "rating": 8.0, "genre": "science fiction", "title": "The Terminator"},
82+
),
83+
Document(
84+
page_content="A cowboy doll is profoundly threatened when a new spaceman action figure replaces him as the top toy in a boy's room.",
85+
metadata={"year": 1995, "rating": 8.3, "genre": "animation", "title": "Toy Story"},
86+
),
87+
Document(
88+
page_content="A young wizard, Harry Potter, begins his journey at Hogwarts School of Witchcraft and Wizardry, where he learns of his magical heritage.",
89+
metadata={"year": 2001, "rating": 7.6, "genre": "fantasy", "title": "Harry Potter and the Sorcerer's Stone"},
90+
),
91+
Document(
92+
page_content="A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.",
93+
metadata={"year": 2014, "rating": 8.6, "genre": "science fiction", "title": "Interstellar"},
94+
),
95+
Document(
96+
page_content="A former Roman General seeks revenge against the corrupt emperor who murdered his family and sent him into slavery.",
97+
metadata={"year": 2000, "rating": 8.5, "genre": "action", "title": "Gladiator"},
98+
),
99+
Document(
100+
page_content="A young lion prince is exiled from his kingdom and must learn the true meaning of responsibility and bravery.",
101+
metadata={"year": 1994, "rating": 8.5, "genre": "animation", "title": "The Lion King"},
102+
),
103+
]
104+
105+
# Generate embeddings *before* creating the ElasticsearchStore
106+
texts = [doc.page_content for doc in docs]
107+
metadatas = [doc.metadata for doc in docs]
108+
doc_embeddings = embeddings.embed_documents(texts)
109+
110+
es_store = ElasticsearchStore(
111+
es_cloud_id=ELASTIC_CLOUD_ID,
112+
es_user=ELASTIC_USERNAME,
113+
es_password=ELASTIC_PASSWORD,
114+
index_name=ELASTIC_INDEX_NAME,
115+
embedding=embeddings,
116+
)
117+
118+
es_store.add_embeddings(text_embeddings=list(zip(texts, doc_embeddings)), metadatas=metadatas)
119+
120+
121+
122+
# --- Create the Self-Query Retriever (Using LLM) ---
123+
retriever = SelfQueryRetriever.from_llm(
124+
llm,
125+
es_store,
126+
"Search for movies",
127+
metadata_field_info,
128+
verbose=True,
129+
)
130+
131+
while True:
132+
# Prompt the user for a query
133+
query = input("\nEnter your search query (or type 'exit' to quit): ")
134+
135+
# Exit the loop if the user types 'exit'
136+
if query.lower() == 'exit':
137+
break
138+
139+
# Execute the query and print the results
140+
print(f"\nQuery: {query}")
141+
docs = retriever.invoke(query)
142+
print(f"Found {len(docs)} documents:")
143+
for doc in docs:
144+
print(doc.page_content)
145+
print(doc.metadata)
146+
print("-" * 20)

0 commit comments

Comments
 (0)