## TiDB Vector

> [TiDB Cloud](https://tidbcloud.com/), is a comprehensive Database-as-a-Service (DBaaS) solution, that provides dedicated and serverless options. TiDB Serverless is now integrating a built-in vector search into the MySQL landscape. With this enhancement, you can seamlessly develop AI applications using TiDB Serverless without the need for a new database or additional technical stacks. Be among the first to experience it by joining the waitlist for the private beta at [https://tidb.cloud/ai](https://tidb.cloud/ai).

This notebook provides a detailed guide on utilizing the TiDB Vector functionality, showcasing its features and practical applications.

## Setting up environments[​](#setting-up-environments "Direct link to Setting up environments")

Begin by installing the necessary packages.

```
%pip install langchain%pip install langchain-openai%pip install pymysql%pip install tidb-vector
```

Configure both the OpenAI and TiDB host settings that you will need. In this notebook, we will follow the standard connection method provided by TiDB Cloud to establish a secure and efficient database connection.

```
# Here we useimport getpassimport getpassimport osos.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")# copy from tidb cloud consoletidb_connection_string_template = "mysql+pymysql://<USER>:<PASSWORD>@<HOST>:4000/<DB>?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true"# tidb_connection_string_template = "mysql+pymysql://root:<PASSWORD>@34.212.137.91:4000/test"tidb_password = getpass.getpass("Input your TiDB password:")tidb_connection_string = tidb_connection_string_template.replace(    "<PASSWORD>", tidb_password)
```

Prepare the following data

```
from langchain.text_splitter import CharacterTextSplitterfrom langchain_community.document_loaders import TextLoaderfrom langchain_community.vectorstores import TiDBVectorStorefrom langchain_openai import OpenAIEmbeddings
```

```
loader = TextLoader("../../modules/state_of_the_union.txt")documents = loader.load()text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)docs = text_splitter.split_documents(documents)embeddings = OpenAIEmbeddings()
```

## Semantic similarity search[​](#semantic-similarity-search "Direct link to Semantic similarity search")

TiDB supports both cosine and Euclidean distances (‘cosine’, ‘l2’), with ‘cosine’ being the default choice.

The code snippet below creates a table named `TABLE_NAME` in TiDB, optimized for vector searching. Upon successful execution of this code, you will be able to view and access the `TABLE_NAME` table directly within your TiDB database.

```
TABLE_NAME = "semantic_embeddings"db = TiDBVectorStore.from_documents(    documents=docs,    embedding=embeddings,    table_name=TABLE_NAME,    connection_string=tidb_connection_string,    distance_strategy="cosine",  # default, another option is "l2")
```

```
query = "What did the president say about Ketanji Brown Jackson"docs_with_score = db.similarity_search_with_score(query, k=3)
```

Please note that a lower cosine distance indicates higher similarity.

```
for doc, score in docs_with_score:    print("-" * 80)    print("Score: ", score)    print(doc.page_content)    print("-" * 80)
```

```
--------------------------------------------------------------------------------Score:  0.18459301498220004Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.----------------------------------------------------------------------------------------------------------------------------------------------------------------Score:  0.2172729943284636A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. And if we are to advance liberty and justice, we need to secure the Border and fix the immigration system. We can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling.  We’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers.  We’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster. We’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders.----------------------------------------------------------------------------------------------------------------------------------------------------------------Score:  0.2262166799003692And for our LGBTQ+ Americans, let’s finally get the bipartisan Equality Act to my desk. The onslaught of state laws targeting transgender Americans and their families is wrong. As I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential. While it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice. And soon, we’ll strengthen the Violence Against Women Act that I first wrote three decades ago. It is important for us to show the nation that we can come together and do big things. So tonight I’m offering a Unity Agenda for the Nation. Four big things we can do together.  First, beat the opioid epidemic.--------------------------------------------------------------------------------
```

Additionally, the similarity\_search\_with\_relevance\_scores method can be used to obtain relevance scores, where a higher score indicates greater similarity.

```
docs_with_relevance_score = db.similarity_search_with_relevance_scores(query, k=2)for doc, score in docs_with_relevance_score:    print("-" * 80)    print("Score: ", score)    print(doc.page_content)    print("-" * 80)
```

```
--------------------------------------------------------------------------------Score:  0.8154069850178Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.----------------------------------------------------------------------------------------------------------------------------------------------------------------Score:  0.7827270056715364A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. And if we are to advance liberty and justice, we need to secure the Border and fix the immigration system. We can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling.  We’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers.  We’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster. We’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders.--------------------------------------------------------------------------------
```

## Filter with metadata

perform searches using metadata filters to retrieve a specific number of nearest-neighbor results that align with the applied filters.

Each vector in the TiDB Vector Store can be paired with metadata, structured as key-value pairs within a JSON object. The keys are strings, and the values can be of the following types:

*   String
*   Number (integer or floating point)
*   Booleans (true, false)

For instance, consider the following valid metadata payloads:

```
{    "page": 12,    "book_tile": "Siddhartha"}
```

The available filters include:

*   \\$or - Selects vectors that meet any one of the given conditions.
*   \\$and - Selects vectors that meet all of the given conditions.
*   \\$eq - Equal to
*   \\$ne - Not equal to
*   \\$gt - Greater than
*   \\$gte - Greater than or equal to
*   \\$lt - Less than
*   \\$lte - Less than or equal to
*   \\$in - In array
*   \\$nin - Not in array

Assuming one vector with metada:

```
{    "page": 12,    "book_tile": "Siddhartha"}
```

The following metadata filters will match the vector

```
{"page": 12}{"page":{"$eq": 12}}{"page":{"$in": [11, 12, 13]}}{"page":{"$nin": [13]}}{"page":{"$lt": 11}}{    "$or": [{"page": 11}, {"page": 12}],    "$and": [{"page": 12}, {"page": 13}],}
```

Please note that each key-value pair in the metadata filters is treated as a separate filter clause, and these clauses are combined using the AND logical operator.

```
db.add_texts(    texts=[        "TiDB Vector offers advanced, high-speed vector processing capabilities, enhancing AI workflows with efficient data handling and analytics support.",        "TiDB Vector, starting as low as $10 per month for basic usage",    ],    metadatas=[        {"title": "TiDB Vector functionality"},        {"title": "TiDB Vector Pricing"},    ],)
```

```
[UUID('c782cb02-8eec-45be-a31f-fdb78914f0a7'), UUID('08dcd2ba-9f16-4f29-a9b7-18141f8edae3')]
```

```
docs_with_score = db.similarity_search_with_score(    "Introduction to TiDB Vector", filter={"title": "TiDB Vector functionality"}, k=4)for doc, score in docs_with_score:    print("-" * 80)    print("Score: ", score)    print(doc.page_content)    print("-" * 80)
```

```
--------------------------------------------------------------------------------Score:  0.12761409169211535TiDB Vector offers advanced, high-speed vector processing capabilities, enhancing AI workflows with efficient data handling and analytics support.--------------------------------------------------------------------------------
```

### Using as a Retriever[​](#using-as-a-retriever "Direct link to Using as a Retriever")

In Langchain, a retriever is an interface that retrieves documents in response to an unstructured query, offering a broader functionality than a vector store. The code below demonstrates how to utilize TiDB Vector as a retriever.

```
retriever = db.as_retriever(    search_type="similarity_score_threshold",    search_kwargs={"k": 3, "score_threshold": 0.8},)docs_retrieved = retriever.get_relevant_documents(query)for doc in docs_retrieved:    print("-" * 80)    print(doc.page_content)    print("-" * 80)
```

```
--------------------------------------------------------------------------------Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.--------------------------------------------------------------------------------
```

## Advanced Use Case Scenario[​](#advanced-use-case-scenario "Direct link to Advanced Use Case Scenario")

Let’s look a advanced use case - a travel agent is crafting a custom travel report for clients who desire airports with specific amenities such as clean lounges and vegetarian options. The process involves: - A semantic search within airport reviews to extract airport codes meeting these amenities. - A subsequent SQL query that joins these codes with route information, detailing airlines and destinations aligned with the clients’ preferences.

First, let’s prepare some airpod related data

```
# create table to store airplan datadb.tidb_vector_client.execute(    """CREATE TABLE airplan_routes (        id INT AUTO_INCREMENT PRIMARY KEY,        airport_code VARCHAR(10),        airline_code VARCHAR(10),        destination_code VARCHAR(10),        route_details TEXT,        duration TIME,        frequency INT,        airplane_type VARCHAR(50),        price DECIMAL(10, 2),        layover TEXT    );""")# insert some data into Routes and our vector tabledb.tidb_vector_client.execute(    """INSERT INTO airplan_routes (        airport_code,        airline_code,        destination_code,        route_details,        duration,        frequency,        airplane_type,        price,        layover    ) VALUES     ('JFK', 'DL', 'LAX', 'Non-stop from JFK to LAX.', '06:00:00', 5, 'Boeing 777', 299.99, 'None'),    ('LAX', 'AA', 'ORD', 'Direct LAX to ORD route.', '04:00:00', 3, 'Airbus A320', 149.99, 'None'),    ('EFGH', 'UA', 'SEA', 'Daily flights from SFO to SEA.', '02:30:00', 7, 'Boeing 737', 129.99, 'None');    """)db.add_texts(    texts=[        "Clean lounges and excellent vegetarian dining options. Highly recommended.",        "Comfortable seating in lounge areas and diverse food selections, including vegetarian.",        "Small airport with basic facilities.",    ],    metadatas=[        {"airport_code": "JFK"},        {"airport_code": "LAX"},        {"airport_code": "EFGH"},    ],)
```

```
[UUID('6dab390f-acd9-4c7d-b252-616606fbc89b'), UUID('9e811801-0e6b-4893-8886-60f4fb67ce69'), UUID('f426747c-0f7b-4c62-97ed-3eeb7c8dd76e')]
```

Finding Airports with Clean Facilities and Vegetarian Options via Vector Search

```
retriever = db.as_retriever(    search_type="similarity_score_threshold",    search_kwargs={"k": 3, "score_threshold": 0.85},)semantic_query = "Could you recommend a US airport with clean lounges and good vegetarian dining options?"reviews = retriever.get_relevant_documents(semantic_query)for r in reviews:    print("-" * 80)    print(r.page_content)    print(r.metadata)    print("-" * 80)
```

```
--------------------------------------------------------------------------------Clean lounges and excellent vegetarian dining options. Highly recommended.{'airport_code': 'JFK'}----------------------------------------------------------------------------------------------------------------------------------------------------------------Comfortable seating in lounge areas and diverse food selections, including vegetarian.{'airport_code': 'LAX'}--------------------------------------------------------------------------------
```

```
# Extracting airport codes from the metadataairport_codes = [review.metadata["airport_code"] for review in reviews]# Executing a query to get the airport detailssearch_query = "SELECT * FROM airplan_routes WHERE airport_code IN :codes"params = {"codes": tuple(airport_codes)}airport_details = db.tidb_vector_client.execute(search_query, params)airport_details.get("result")
```

```
[(1, 'JFK', 'DL', 'LAX', 'Non-stop from JFK to LAX.', datetime.timedelta(seconds=21600), 5, 'Boeing 777', Decimal('299.99'), 'None'), (2, 'LAX', 'AA', 'ORD', 'Direct LAX to ORD route.', datetime.timedelta(seconds=14400), 3, 'Airbus A320', Decimal('149.99'), 'None')]
```

Alternatively, we can streamline the process by utilizing a single SQL query to accomplish the search in one step.

```
search_query = f"""    SELECT         VEC_Cosine_Distance(se.embedding, :query_vector) as distance,         ar.*,        se.document as airport_review    FROM         airplan_routes ar    JOIN         {TABLE_NAME} se ON ar.airport_code = JSON_UNQUOTE(JSON_EXTRACT(se.meta, '$.airport_code'))    ORDER BY distance ASC     LIMIT 5;"""query_vector = embeddings.embed_query(semantic_query)params = {"query_vector": str(query_vector)}airport_details = db.tidb_vector_client.execute(search_query, params)airport_details.get("result")
```

```
[(0.1219207353407008, 1, 'JFK', 'DL', 'LAX', 'Non-stop from JFK to LAX.', datetime.timedelta(seconds=21600), 5, 'Boeing 777', Decimal('299.99'), 'None', 'Clean lounges and excellent vegetarian dining options. Highly recommended.'), (0.14613754359804654, 2, 'LAX', 'AA', 'ORD', 'Direct LAX to ORD route.', datetime.timedelta(seconds=14400), 3, 'Airbus A320', Decimal('149.99'), 'None', 'Comfortable seating in lounge areas and diverse food selections, including vegetarian.'), (0.19840519342700513, 3, 'EFGH', 'UA', 'SEA', 'Daily flights from SFO to SEA.', datetime.timedelta(seconds=9000), 7, 'Boeing 737', Decimal('129.99'), 'None', 'Small airport with basic facilities.')]
```

```
# clean updb.tidb_vector_client.execute("DROP TABLE airplan_routes")
```

```
{'success': True, 'result': 0, 'error': None}
```

## Delete

You can remove the TiDB Vector Store by using the `.drop_vectorstore()` method.