Tutorial Lengkap Pinecone: Vector Database untuk AI dan Semantic Search
Pinecone adalah managed vector database yang dirancang khusus untuk menyimpan, mengindeks, dan melakukan pencarian similarity pada data vektor berdimensi tinggi. Dalam ekosistem AI modern, Pinecone menjadi salah satu pilihan utama untuk membangun sistem Retrieval-Augmented Generation (RAG), semantic search, recommendation engine, dan berbagai aplikasi berbasis embedding.
Berbeda dengan database tradisional yang mengandalkan exact match, Pinecone memungkinkan pencarian berdasarkan kemiripan semantik. Ketika Anda mengubah teks, gambar, atau data lainnya menjadi vektor embedding, Pinecone dapat menemukan item yang paling mirip dalam hitungan milidetik, bahkan pada skala miliaran vektor.
Dalam tutorial ini, kita akan mempelajari cara menggunakan Pinecone dari instalasi hingga penggunaan lanjutan, termasuk integrasi dengan model embedding populer dan membangun pipeline RAG yang lengkap.
Mengapa Memilih Pinecone?
Sebelum masuk ke implementasi, ada beberapa alasan mengapa Pinecone menjadi pilihan populer untuk vector database:
Instalasi dan Setup
Prasyarat
Pastikan Anda memiliki Python 3.8 atau lebih baru terinstal di sistem Anda.
Instalasi Pinecone Client
pip install pinecone-client
Untuk instalasi dengan dependensi tambahan yang berguna:
pip install pinecone-client sentence-transformers openai python-dotenv
Membuat Akun dan API Key
.env# .env
PINECONEAPIKEY=your-api-key-here
Inisialisasi Client
import os
from dotenv import loaddotenv
from pinecone import Pinecone
loaddotenv()
pc = Pinecone(apikey=os.getenv("PINECONEAPIKEY"))
Verifikasi koneksi
print("Indexes yang tersedia:", pc.listindexes().names())
Konsep Dasar Pinecone
Index
Index adalah unit penyimpanan utama di Pinecone, mirip dengan "table" di database relasional. Setiap index dikonfigurasi dengan dimensi vektor tertentu dan metrik similarity.
Namespace
Namespace memungkinkan Anda mempartisi data dalam satu index. Setiap namespace bersifat independen, sehingga query pada satu namespace tidak akan mengembalikan hasil dari namespace lain.
Vektor dan Metadata
Setiap record di Pinecone terdiri dari:
- ID: Identifier unik untuk vektor
- Values: Array numerik (vektor embedding)
- Metadata: Data tambahan berupa key-value pairs yang dapat difilter
Metrik Similarity
Pinecone mendukung tiga metrik:
- Cosine: Mengukur sudut antara dua vektor (paling umum untuk teks)
- Euclidean: Mengukur jarak geometris antara dua titik
- Dot Product: Mengukur proyeksi satu vektor ke vektor lainnya
Basic Usage
Membuat Index
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(apikey=os.getenv("PINECONEAPIKEY"))
indexname = "tutorial-index"
if indexname not in pc.listindexes().names():
pc.createindex(
name=indexname,
dimension=384, # Sesuaikan dengan model embedding Anda
metric="cosine",
spec=ServerlessSpec(
cloud="aws",
region="us-east-1"
)
)
print(f"Index '{indexname}' berhasil dibuat")
Hubungkan ke index
index = pc.Index(indexname)
Lihat statistik index
print(index.describeindexstats())
Menyimpan Vektor (Upsert)
# Upsert vektor sederhana
vectors = [
{
"id": "doc-1",
"values": [0.1, 0.2, 0.3, ...], # 384 dimensi
"metadata": {
"title": "Pengantar Machine Learning",
"category": "tutorial",
"language": "id"
}
},
{
"id": "doc-2",
"values": [0.4, 0.5, 0.6, ...],
"metadata": {
"title": "Deep Learning Fundamentals",
"category": "article",
"language": "en"
}
}
]
index.upsert(vectors=vectors)
Upsert dengan Embedding Model
Dalam prakteknya, Anda akan menggunakan model embedding untuk menghasilkan vektor:
from sentencetransformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
documents = [
{"id": "doc-1", "text": "Machine learning adalah cabang dari kecerdasan buatan", "category": "ai"},
{"id": "doc-2", "text": "Python adalah bahasa pemrograman yang populer untuk data science", "category": "programming"},
{"id": "doc-3", "text": "Neural network terinspirasi dari cara kerja otak manusia", "category": "ai"},
{"id": "doc-4", "text": "Database relasional menggunakan tabel untuk menyimpan data", "category": "database"},
{"id": "doc-5", "text": "Natural Language Processing memproses dan memahami bahasa manusia", "category": "ai"},
]
Generate embeddings
texts = [doc["text"] for doc in documents]
embeddings = model.encode(texts)
Siapkan data untuk upsert
vectors
toupsert = []
for doc, embedding in zip(documents, embeddings):
vectors
toupsert.append({
"id": doc["id"],
"values": embedding.tolist(),
"metadata": {
"text": doc["text"],
"category": doc["category"]
}
})
Upsert ke Pinecone
index.upsert(vectors=vectors
toupsert)
print(f"Berhasil menyimpan {len(vectors
toupsert)} vektor")
Melakukan Query (Pencarian Similarity)
# Query menggunakan teks
querytext = "Bagaimana cara kerja artificial intelligence?"
queryembedding = model.encode(querytext).tolist()
results = index.query(
vector=queryembedding,
topk=3,
includemetadata=True
)
print(f"Query: {querytext}\n")
for match in results["matches"]:
print(f"Score: {match['score']:.4f}")
print(f"Text: {match['metadata']['text']}")
print(f"Category: {match['metadata']['category']}")
print()
Output:
Query: Bagaimana cara kerja artificial intelligence?
Score: 0.7823
Text: Machine learning adalah cabang dari kecerdasan buatan
Category: ai
Score: 0.6541
Text: Neural network terinspirasi dari cara kerja otak manusia
Category: ai
Score: 0.6102
Text: Natural Language Processing memproses dan memahami bahasa manusia
Category: ai
Query dengan Metadata Filter
# Hanya cari dalam kategori tertentu
results = index.query(
vector=queryembedding,
topk=3,
includemetadata=True,
filter={
"category": {"$eq": "programming"}
}
)
Filter dengan kondisi kompleks
results = index.query(
vector=queryembedding,
topk=5,
includemetadata=True,
filter={
"$and": [
{"category": {"$in": ["ai", "programming"]}},
{"language": {"$eq": "id"}}
]
}
)
Operasi CRUD Lainnya
# Fetch vektor berdasarkan ID
fetched = index.fetch(ids=["doc-1", "doc-2"])
print(fetched)
Update metadata vektor
index.update(
id="doc-1",
setmetadata={"category": "machine-learning", "updated": True}
)
Hapus vektor berdasarkan ID
index.delete(ids=["doc-4"])
Hapus berdasarkan filter metadata
index.delete(filter={"category": {"$eq": "deprecated"}})
Hapus semua vektor dalam namespace
index.delete(deleteall=True, namespace="old-data")
Advanced Usage
Batch Upsert untuk Data Besar
Ketika bekerja dengan dataset besar, sebaiknya upsert dilakukan dalam batch:
import itertools
def chunks(iterable, batchsize=100):
it = iter(iterable)
chunk = list(itertools.islice(it, batchsize))
while chunk:
yield chunk
chunk = list(itertools.islice(it, batchsize))
Misalkan Anda punya ribuan dokumen
largedataset = [...] # List of documents
allvectors = []
for i, doc in enumerate(largedataset):
embedding = model.encode(doc["text"]).tolist()
allvectors.append({
"id": f"doc-{i}",
"values": embedding,
"metadata": {"text": doc["text"], "source": doc["source"]}
})
Upsert dalam batch
for batch in chunks(allvectors, batchsize=100):
index.upsert(vectors=batch)
print(f"Total vektor yang diupsert: {len(allvectors)}")
Menggunakan Namespace
# Simpan data ke namespace berbeda
index.upsert(
vectors=productvectors,
namespace="products"
)
index.upsert(
vectors=articlevectors,
namespace="articles"
)
Query pada namespace tertentu
results = index.query(
vector=queryembedding,
topk=5,
namespace="products",
includemetadata=True
)
Statistik per namespace
stats = index.describeindexstats()
print(stats)
{'dimension': 384, 'namespaces': {'products': {'vectorcount': 1000}, 'articles': {'vectorcount': 500}}}
Membangun RAG Pipeline dengan Pinecone
Berikut contoh lengkap membangun sistem RAG menggunakan Pinecone dan OpenAI:
import os
from pinecone import Pinecone, ServerlessSpec
from openai import OpenAI
from sentencetransformers import SentenceTransformer
Inisialisasi
pc = Pinecone(apikey=os.getenv("PINECONEAPIKEY"))
openaiclient = OpenAI(apikey=os.getenv("OPENAIAPIKEY"))
embedmodel = SentenceTransformer("all-MiniLM-L6-v2")
INDEXNAME = "rag-knowledge-base"
NAMESPACE = "documents"
Buat index jika belum ada
if INDEXNAME not in pc.listindexes().names():
pc.createindex(
name=INDEXNAME,
dimension=384,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1")
)
index = pc.Index(INDEXNAME)
def ingestdocuments(documents):
"""Ingest dokumen ke Pinecone"""
vectors = []
for i, doc in enumerate(documents):
# Chunking sederhana
textchunks = splittext(doc["content"], chunksize=500, overlap=50)
for j, chunk in enumerate(textchunks):
embedding = embedmodel.encode(chunk).tolist()
vectors.append({
"id": f"{doc['id']}-chunk-{j}",
"values": embedding,
"metadata": {
"text": chunk,
"source": doc["source"],
"title": doc["title"]
}
})
# Batch upsert
for k in range(0, len(vectors), 100):
batch = vectors[k:k+100]
index.upsert(vectors=batch, namespace=NAMESPACE)
return len(vectors)
def splittext(text, chunksize=500, overlap=50):
"""Split teks menjadi chunk dengan overlap"""
words = text.split()
chunks = []
for i in range(0, len(words), chunksize - overlap):
chunk = " ".join(words[i:i + chunksize])
if chunk:
chunks.append(chunk)
return chunks
def retrievecontext(query, topk=5):
"""Retrieve konteks relevan dari Pinecone"""
queryembedding = embedmodel.encode(query).tolist()
results = index.query(
vector=queryembedding,
topk=topk,
includemetadata=True,
namespace=NAMESPACE
)
contexts = []
for match in results["matches"]:
if match["score"] > 0.3: # Threshold minimum
contexts.append({
"text": match["metadata"]["text"],
"source": match["metadata"]["source"],
"score": match["score"]
})
return contexts
def generateanswer(query, contexts):
"""Generate jawaban menggunakan LLM dengan konteks dari Pinecone"""
contexttext = "\n\n".join([
f"[Source: {ctx['source']}]\n{ctx['text']}"
for ctx in contexts
])
response = openaiclient.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": (
"Anda adalah asisten yang menjawab pertanyaan berdasarkan konteks yang diberikan. "
"Jawab hanya berdasarkan informasi dalam konteks. "
"Jika informasi tidak tersedia dalam konteks, katakan bahwa Anda tidak menemukan informasinya."
)
},
{
"role": "user",
"content": f"Konteks:\n{contexttext}\n\nPertanyaan: {query}"
}
],
temperature=0.1
)
return response.choices[0].message.content
def ragquery(query):
"""Pipeline RAG lengkap"""
print(f"Query: {query}")
# Retrieve
contexts = retrievecontext(query)
print(f"Ditemukan {len(contexts)} konteks relevan")
# Generate
answer = generateanswer(query, contexts)
print(f"\nJawaban: {answer}")
# Sertakan sumber
print("\nSumber:")
for ctx in contexts:
print(f" - {ctx['source']} (score: {ctx['score']:.4f})")
return answer
Contoh penggunaan
knowledgebase = [
{
"id": "kb-1",
"title": "Panduan Python",
"source": "docs/python-guide.md",
"content": "Python adalah bahasa pemrograman tingkat tinggi yang mudah dipelajari..."
},
{
"id": "kb-2",
"title": "Machine Learning Basics",
"source": "docs/ml-basics.md",
"content": "Machine learning adalah subset dari artificial intelligence..."
}
]
Ingest
count = ingestdocuments(knowledgebase)
print(f"Berhasil ingest {count} chunks")
Query
answer = ragquery("Apa itu machine learning?")
Hybrid Search (Sparse-Dense)
Pinecone mendukung hybrid search yang menggabungkan semantic search (dense vectors) dengan keyword search (sparse vectors):
from pineconetext.sparse import BM25Encoder
Inisialisasi BM25 encoder untuk sparse vectors
bm25 = BM25Encoder()
Fit BM25 pada corpus
corpus = [doc["text"] for doc in documents]
bm25.fit(corpus)
Generate sparse dan dense vectors
query = "machine learning tutorial python"
Dense embedding
densevector = embedmodel.encode(query).tolist()
Sparse embedding (BM25)
sparsevector = bm25.encodequeries(query)
Hybrid query
results = index.query(
vector=densevector,
sparsevector=sparsevector,
topk=10,
includemetadata=True,
alpha=0.5 # Balance antara dense dan sparse (0 = sparse only, 1 = dense only)
)
Integrasi dengan LangChain
from langchainpinecone import PineconeVectorStore
from langchaincommunity.embeddings import HuggingFaceEmbeddings
from langchain.textsplitter import RecursiveCharacterTextSplitter
from langchaincommunity.documentloaders import TextLoader
Load dokumen
loader = TextLoader("knowledgebase.txt")
documents = loader.load()
Split dokumen
textsplitter = RecursiveCharacterTextSplitter(
chunksize=1000,
chunkoverlap=200
)
docs = textsplitter.splitdocuments(documents)
Embedding model
embeddings = HuggingFaceEmbeddings(
modelname="all-MiniLM-L6-v2"
)
Buat vector store
vectorstore = PineconeVectorStore.fromdocuments(
documents=docs,
embedding=embeddings,
indexname="langchain-index",
namespace="docs"
)
Similarity search
results = vectorstore.similaritysearch(
"Apa itu neural network?",
k=3
)
for doc in results:
print(doc.pagecontent)
print()
Gunakan sebagai retriever
retriever = vectorstore.asretriever(
searchtype="similarity",
searchkwargs={"k": 5}
)
Integrasi dengan LlamaIndex
from llamaindex.core import VectorStoreIndex, SimpleDirectoryReader
from llama
index.vectorstores.pinecone import PineconeVectorStore
from pinecone import Pinecone
pc = Pinecone(api
key=os.getenv("PINECONEAPIKEY"))
pineconeindex = pc.Index("llamaindex-demo")
Buat vector store
vectorstore = PineconeVectorStore(pineconeindex=pineconeindex)
Load dan index dokumen
documents = SimpleDirectoryReader("./data").loaddata()
index = VectorStoreIndex.fromdocuments(
documents,
vectorstore=vectorstore
)
Query
queryengine = index.asqueryengine()
response = queryengine.query("Jelaskan konsep transfer learning")
print(response)
Best Practices
1. Pilih Dimensi Embedding yang Tepat
Dimensi embedding harus sesuai dengan model yang Anda gunakan:
| Model | Dimensi | Kasus Penggunaan |
|-------|---------|-----------------|
| all-MiniLM-L6-v2 | 384 | General purpose, ringan |
| text-embedding-3-small | 1536 | OpenAI, keseimbangan performa-biaya |
| text-embedding-3-large | 3072 | OpenAI, akurasi maksimal |
| BAAI/bge-large-en-v1.5 | 1024 | Open source, performa tinggi |
2. Strategi Chunking yang Efektif
from langchain.textsplitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk
size=512,
chunkoverlap=50,
separators=["\n\n", "\n", ". ", " ", ""]
)
Chunk yang terlalu kecil kehilangan konteks
Chunk yang terlalu besar mengaburkan relevansi
256-1024 token adalah range yang baik untuk kebanyakan kasus
3. Manfaatkan Metadata Filter
# Simpan metadata yang berguna untuk filtering
vector = {
"id": "article-123",
"values": embedding,
"metadata": {
"text": chunktext,
"source": "blog",
"date": "2026-01-15",
"language": "id",
"category": "tutorial",
"author": "Ruby Abdullah"
}
}
Kombinasikan vector search dengan metadata filter
results = index.query(
vector=queryembedding,
topk=10,
filter={
"$and": [
{"category": {"$eq": "tutorial"}},
{"language": {"$eq": "id"}}
]
},
includemetadata=True
)
4. Monitoring dan Observability
# Periksa statistik index secara berkala
stats = index.describeindexstats()
print(f"Total vectors: {stats['totalvectorcount']}")
print(f"Dimensi: {stats['dimension']}")
for ns, nsstats in stats.get("namespaces", {}).items():
print(f"Namespace '{ns}': {nsstats['vectorcount']} vectors")
5. Penanganan Error dan Retry
import time
from pinecone.exceptions import PineconeException
def safeupsert(index, vectors, namespace="", maxretries=3):
for attempt in range(maxretries):
try:
index.upsert(vectors=vectors, namespace=namespace)
return True
except PineconeException as e:
if attempt < maxretries - 1:
waittime = 2 attempt
print(f"Retry {attempt + 1}/{maxretries} setelah {waittime}s: {e}")
time.sleep(waittime)
else:
raise
return False
6. Optimasi Biaya
- Gunakan serverless index untuk workload yang bervariasi
- Pilih dimensi embedding yang sesuai kebutuhan (tidak selalu yang terbesar)
- Manfaatkan namespace alih-alih membuat banyak index
- Hapus data yang sudah tidak relevan secara berkala
- Gunakan metadata filter untuk mempersempit pencarian sebelum vector similarity
Kesalahan Umum yang Harus Dihindari
Kesimpulan
Pinecone menyediakan solusi vector database yang handal dan mudah digunakan untuk berbagai aplikasi AI. Dari semantic search sederhana hingga pipeline RAG yang kompleks, Pinecone menawarkan performa tinggi tanpa kerumitan mengelola infrastruktur.
Hal-hal penting yang perlu diingat:
- Pilih model embedding dan dimensi yang sesuai dengan kebutuhan
- Manfaatkan metadata filtering untuk mempersempit pencarian
- Gunakan batch processing untuk operasi pada data besar
- Terapkan namespace untuk mengorganisir data
- Monitor penggunaan dan optimasi biaya secara berkala
Dengan pemahaman dasar dan teknik lanjutan yang dibahas dalam tutorial ini, Anda sudah siap membangun aplikasi AI yang memanfaatkan vector search secara efektif menggunakan Pinecone.