Memproses dokumen
Pada tanggal 25 April 2023, Jacob Marks, Ph.D., seorang penulis dan pakar dalam bidang pembelajaran mesin, mempublikasikan sebuah artikel menarik di towardsdatascience.com. Artikel tersebut berjudul “How I Turned My Company’s Docs into a Searchable Database with OpenAI” dan membahas bagaimana ia mengubah dokumen perusahaan menjadi database vektor yang dapat dicari secara semantik dengan menggunakan OpenAI.
Jadi, dalam artikel tersebut, Marks berbagi langkah-langkah dan bahan yang diperlukan untuk mengimplementasikan pencarian semantik untuk dokumen Anda sendiri. Ini adalah artikel yang menarik dan bermanfaat bagi siapa saja yang tertarik dalam bidang pembelajaran mesin dan teknologi pencarian dokumen.
Selama enam bulan terakhir, Mister Jacob telah bekerja di sebuah startup seri A bernama Voxel51 yang merupakan pencipta dari toolkit visi open source computer FiftyOne. Sebagai seorang insinyur pembelajaran mesin dan pengembang evangelis, tugas saya adalah mendengarkan komunitas sumber terbuka kami dan memberikan apa yang mereka butuhkan – fitur baru, integrasi, tutorial, workshop, dan lain-lain.
Beberapa minggu yang lalu, mereka (Mr. Jacob dan timnya) menambahkan dukungan asli untuk mesin pencari vektor dan kueri kesamaan teks pada FiftyOne, sehingga pengguna dapat menemukan gambar paling relevan dalam dataset mereka (yang seringkali sangat besar – berisi jutaan atau puluhan juta sampel) melalui kueri bahasa alami yang sederhana.
Hal ini menempatkan mereka pada posisi yang menarik: sekarang orang yang menggunakan FiftyOne dapat dengan mudah mencari dataset dengan kueri bahasa alami, tetapi menggunakan dokumentasi kami masih memerlukan pencarian kata kunci tradisional.
jadi, mereka ini memiliki banyak dokumen, yang memiliki kelebihan dan kekurangan. Sebagai pengguna sendiri, terkadang saya merasa bahwa dengan jumlah dokumentasi yang begitu banyak, menemukan apa yang saya cari memerlukan waktu yang lebih lama dari yang saya inginkan.
Mr. Jacob tidak akan membiarkan ini terjadi … jadi ia membangun hal itu pada waktu luang aja:

Beginilah cara seseorang mengubah dokumen perusahaan menjadi database pencarian yang semantik:
1. Mengubah semua dokumen ke dalam format yang seragam
2. Membagi dokumen menjadi blok dan menambahkan pembersihan otomatis
3. Menghitung embedding untuk setiap blok
4. Membuat indeks vektor dari embedding tersebut
5. Mendefinisikan kueri indeks
6. Mengemas semuanya dalam antarmuka baris perintah yang ramah pengguna dan API PythonAnda bisa menemukan semua kode untuk posting ini di repo voxel51/fiftyone-docs-search, dan mudah untuk menginstal paket tersebut secara lokal dengan pip install -e ..
Yang lebih baik lagi, jika Anda ingin menerapkan pencarian semantik untuk situs web Anda sendiri menggunakan metode ini, Anda dapat mengikuti tutorial berikut! Berikut adalah bahan-bahan yang Anda butuhkan:
1. Menginstal paket Python openai dan membuat akun: Anda akan menggunakan akun ini untuk mengirim dokumen dan kueri Anda ke endpoint inferensi, yang akan mengembalikan vektor embedding untuk setiap teks.
2. Menginstal paket Python qdrant-client dan meluncurkan server Qdrant melalui Docker: Anda akan menggunakan Qdrant untuk membuat indeks vektor yang terhosting secara lokal untuk dokumen, yang akan berjalan melawan kueri. Layanan Qdrant akan berjalan di dalam kontainer Docker.
Mengubah Dokumen ke dalam Format yang Seragam.
Dokumen perusahaan dimuat sebagai dokumen HTML di https://docs.voxel51.com. Sebagai titik awal yang wajar, dapat diunduh dokumen ini dengan menggunakan perpustakaan Python “requests” dan mengurai dokumen dengan Beautiful Soup.
Namun, sebagai pengembang (dan penulis banyak dokumen kami), ia berpikir dapat melakukan yang lebih baik. Ia sudah memiliki salinan kerja repositori GitHub di komputernya yang berisi semua file mentah yang digunakan untuk menghasilkan dokumen HTML. Beberapa dokumen kami ditulis dalam Sphinx ReStructured Text (RST), sedangkan yang lain seperti tutorial dikonversi ke HTML dari notebook Jupyter.
Ia mengira (yang keliru) semakin dekat dengan teks mentah file RST dan Jupyter, semakin sederhana hal itu akan menjadi.
RST
Dalam dokumen RST, bagian-bagian dibatasi oleh baris yang terdiri dari hanya tanda sama dengan (=), tanda minus (-) atau garis bawah (_). Sebagai contoh, ini adalah dokumen dari Panduan Pengguna FiftyOne yang mengandung ketiga tanda pemisah tersebut:

Kemudian, ia dapat menghapus semua kata kunci RST, seperti toctree, code-block, dan button_link (ada banyak lagi), serta :, ::, dan .. yang menemani kata kunci, awal blok baru, atau deskriptor blok.
Link-link juga mudah diurus:
no_links_section = re.sub(r"<[^>]+>_?","", section)Namun, masalah mulai muncul ketika ia ingin mengekstrak anchor dari file RST. Banyak bagian yang memiliki anchor yang ditentukan secara eksplisit, sedangkan yang lain dibiarkan diinferensikan saat konversi ke HTML.
Berikut adalah contoh:
.. _brain-embeddings-visualization:
Visualizing embeddings
The FiftyOne Brain provides a powerful
:meth:compute_visualization() <fiftyone.brain.compute_visualization> method
that you can use to generate low-dimensional representations of the samples
and/or individual objects in your datasets.
These representations can be visualized natively in the App's
:ref:Embeddings panel <app-embeddings-panel>, where you can interactively
select points of interest and view the corresponding samples/labels of interest
in the :ref:Samples panel <app-samples-panel>, and vice versa.
.. image:: /images/brain/brain-mnist.png
:alt: mnist
:align: center
Ada dua komponen utama dalam visualisasi embedding: metode yang digunakan untuk menghasilkan embedding, dan metode reduksi dimensionalitas yang digunakan untuk menghitung representasi rendah-dimensional dari embedding.
Metode embedding
Parameter embeddings dan model dari :meth:compute_visualization() <fiftyone.brain.compute_visualization> mendukung berbagai cara untuk menghasilkan embedding untuk data Anda:Dalam file brain.rst di dokumen Panduan Pengguna kami (sebagian dari itu diproduksi di atas), bagian Visualizing embeddings memiliki anchor #brain-embeddings-visualization yang ditentukan oleh .. _brain-embeddings-visualization:. Sedangkan, sub-bagian Embedding methods yang langsung mengikuti, diberikan anchor yang dihasilkan secara otomatis.
Kemudian, masalah lain yang muncul adalah cara menangani tabel di RST. Tabel daftar cukup mudah. Sebagai contoh, ini adalah tabel daftar dari lembar trik View Stages kami:
.. list-table::
* - :meth:`match() <fiftyone.core.collections.SampleCollection.match>`
* - :meth:`match_frames() <fiftyone.core.collections.SampleCollection.match_frames>`
* - :meth:`match_labels() <fiftyone.core.collections.SampleCollection.match_labels>`
* - :meth:`match_tags() <fiftyone.core.collections.SampleCollection.match_tags>`Namun, tabel grid bisa menjadi rumit dengan cepat. Tabel grid memberikan fleksibilitas yang besar bagi penulis dokumen, tetapi fleksibilitas ini membuat analisisnya sulit. Ambil contoh tabel ini dari lembar contekan Filtering kami:
| Operation | Command |
|---|---|
| Filepath starts with “/Users” | .. code-block:: ds.match(F(“filepath”).starts_with(“/Users”)) |
| Filepath ends with “10.jpg” or “10.png” | .. code-block:: ds.match(F(“filepath”).ends_with((“10.jpg”, “10.png”))) |
| Label contains string “be” | .. code-block:: ds.filter_labels(“predictions”, F(“label”).contains_str(“be”)) |
| Filepath contains “088” and is JPEG | .. code-block:: ds.match(F(“filepath”).re_match(“088*.jpg”)) |
Dalam sebuah tabel, baris dapat memakan sejumlah baris yang tidak tentu, dan lebar kolom dapat bervariasi. Blok kode dalam sel tabel grid juga sulit untuk diparsing, karena mereka menempati ruang di beberapa baris, sehingga konten mereka terselip dengan konten dari kolom lain. Hal ini berarti blok kode dalam tabel ini perlu direkonstruksi secara efektif selama proses parsing.
Ini bukan akhir dunia. Tetapi juga tidak ideal.
Jupyter
Ternyata mengurai (parse) notebook Jupyter cukup mudah. Saya dapat membaca konten dari notebook Jupyter ke dalam sebuah daftar string, dengan satu string untuk setiap sel (cell).
import json
ifile = "my_notebook.ipynb"
with open(ifile, "r") as f:
contents = f.read()
contents = json.loads(contents)["cells"]
contents = [(" ".join(c["source"]), c['cell_type'] for c in contents]Selain itu, bagian-bagian tersebut ditandai oleh sel Markdown yang dimulai dengan #.
Namun demikian, mengingat tantangan yang ditimbulkan oleh RST, saya memutuskan untuk beralih ke HTML dan memperlakukan semua dokumen kami dengan perlakuan yang sama.
HTML
Saya membangun dokumen HTML dari instalasi lokal saya dengan bash generate_docs.bash, dan mulai mengurai (parsing) mereka dengan Beautiful Soup. Namun, saya segera menyadari bahwa ketika blok kode RST dan tabel dengan kode inline dikonversi menjadi HTML, meskipun mereka dirender dengan benar, HTML-nya sangat sulit untuk diolah. Ambil contoh lembaran petunjuk kami tentang penyaringan.
Ketika dirender di browser, blok kode sebelum bagian Tanggal dan waktu dari lembaran petunjuk penyaringan kami terlihat seperti ini:

Namun, HTML mentah-nya terlihat seperti ini:

Ini bukanlah hal yang tidak mungkin untuk diurai (parse), tetapi jauh dari ideal.
Markdown
Untungnya, saya berhasil mengatasi masalah ini dengan mengonversi semua file HTML menjadi Markdown dengan markdownify. Markdown memiliki beberapa keuntungan utama yang membuatnya cocok untuk tugas ini.
1. Lebih bersih dibandingkan HTML: pemformatan kode disederhanakan dari rangkaian string span menjadi potongan kode inline yang ditandai dengan tanda ` tunggal sebelum dan sesudah, dan blok kode ditandai dengan tiga tanda kutip ``` sebelum dan sesudah. Ini juga membuatnya mudah untuk dibagi menjadi teks dan kode.
2. Masih mempertahankan anchor (pengikat): berbeda dengan RST mentah, Markdown ini termasuk anchor untuk heading section, karena anchor implisit sudah dibuat. Dengan cara ini, saya dapat menghubungkan tidak hanya ke halaman yang berisi hasil, tetapi ke bagian atau sub-bagian tertentu dari halaman itu.
Standardisasi: Markdown menyediakan pemformatan yang sebagian besar seragam untuk dokumen RST dan Jupyter awal, memungkinkan kita memberikan perlakuan yang konsisten pada konten mereka dalam aplikasi pencarian vektor.
Catatan tentang LangChain
Beberapa dari Anda mungkin sudah tahu tentang perpustakaan sumber terbuka LangChain untuk membangun aplikasi dengan LLM, dan mungkin bertanya-tanya mengapa saya tidak hanya menggunakan Document Loader dan Text Splitter LangChain. Jawabannya: saya memerlukan lebih banyak kontrol!
Memproses dokumen
Setelah dokumen dikonversi menjadi Markdown, saya melanjutkan dengan membersihkan kontennya dan membaginya menjadi segmen yang lebih kecil.
Cleaning
Cleaning terutama melibatkan penghapusan elemen yang tidak diperlukan, termasuk:
Header dan footer
Scaffolding baris dan kolom tabel - misalnya | pada | select() | select_by() |
Baris baru tambahan
Tautan
Gambar
Karakter Unicode
Penebalan - yaitu ** teks ** → teksSaya juga menghapus karakter escape yang melarikan diri dari karakter yang memiliki makna khusus di dokumen kami: _ dan *. Yang pertama digunakan dalam banyak nama metode, dan yang terakhir, seperti biasa, digunakan dalam perkalian, pola regex, dan banyak tempat lainnya:
document = document.replace("\_", "_").replace("\*", "*")Splitting dokumen menjadi blok-blok semantik
Setelah konten dokumen kami dibersihkan, saya melanjutkan dengan membagi dokumen menjadi blok-blok yang mudah diakses.
Pertama, saya membagi setiap dokumen menjadi bagian-bagian. Pada pandangan pertama, sepertinya ini dapat dilakukan dengan menemukan setiap baris yang diawali dengan karakter #. Dalam aplikasi saya, saya tidak membedakan antara h1, h2, h3, dan seterusnya (#, ##, ###), jadi memeriksa karakter pertama sudah cukup. Namun, logika ini menimbulkan masalah ketika kami menyadari bahwa # juga digunakan untuk mengizinkan komentar dalam kode Python.
Untuk mengatasi masalah ini, saya membagi dokumen menjadi blok teks dan blok kode:
text_and_code = page_md.split('```')
text = text_and_code[::2]
code = text_and_code[1::2]Maka saya mengidentifikasi awal dari sebuah bagian baru dengan tanda # di awal baris dalam blok teks. Saya mengekstrak judul dan anchor bagian dari baris ini:
def extract_title_and_anchor(header):
header = " ".join(header.split(" ")[1:])
title = header.split("[")[0]
anchor = header.split("(")[1].split(" ")[0]
return title, anchorDan menetapkan setiap blok teks atau kode ke bagian yang sesuai.
Pada awalnya, saya juga mencoba membagi blok teks menjadi paragraf, dengan hipotesis bahwa karena sebuah bagian mungkin berisi informasi tentang banyak topik yang berbeda, embedding untuk seluruh bagian tersebut mungkin tidak serupa dengan embedding untuk sebuah prompt teks yang hanya berkaitan dengan salah satu dari topik tersebut. Namun, pendekatan ini menghasilkan hasil pencarian yang teratas untuk sebagian besar kueri pencarian yang terdiri dari paragraf satu baris saja, yang ternyata tidak terlalu informatif sebagai hasil pencarian.
Coba deh Lihat repositori GitHub yang menyertainya untuk implementasi dari metode-metode ini yang dapat kamu coba pada dokumenmu sendiri!
Cara Embedding Text dan Block Code dengan OpenAI
Setelah dokumen diubah, diproses, dan dibagi menjadi string, saya menghasilkan vektor penanaman untuk setiap blok tersebut. Karena model bahasa besar secara alami fleksibel dan cenderung mampu, saya memutuskan untuk memperlakukan blok teks dan kode dengan cara yang sama sebagai bagian dari teks, dan menanamkannya dengan model yang sama.
Saya menggunakan model teks-embedding-ada-002 dari OpenAI karena mudah digunakan, mencapai kinerja tertinggi dari semua model penanam OpenAI (pada benchmark BEIR), dan juga termurah. Bahkan, harganya sangat murah ($0,0004/1K token) sehingga menghasilkan semua penanaman untuk dokumen FiftyOne hanya memakan beberapa sen saja! Seperti yang dikatakan OpenAI sendiri, “Kami merekomendasikan menggunakan teks-embedding-ada-002 untuk hampir semua kasus penggunaan. Lebih baik, lebih murah, dan lebih mudah digunakan.”
Dengan model penanaman ini, Anda dapat menghasilkan vektor 1536-dimensi yang mewakili setiap prompt input, hingga 8.191 token (sekitar 30.000 karakter).
Untuk memulai, Anda perlu membuat akun OpenAI, menghasilkan kunci API di https://platform.openai.com/account/api-keys, dan mengekspor kunci API ini sebagai variabel lingkungan dengan:
export OPENAI_API_KEY="<MY_API_KEY>"Anda juga perlu menginstal library Python openai:
pip install openaiSaya membuat pembungkus di sekitar API OpenAI yang mengambil masukan teks dan mengembalikan vektor embedding:
MODEL = "text-embedding-ada-002"
def embed_text(text):
response = openai.Embedding.create(
input=text,
model=MODEL
)
embeddings = response['data'][0]['embedding']
return embeddingsUntuk menghasilkan embedding untuk seluruh dokumen, kita hanya perlu menerapkan fungsi ini pada setiap sub-bagian – blok teks dan kode – di seluruh dokumen kita.
Membuat Indeks Vektor Qdrant
Dengan embedding tersedia, saya membuat indeks vektor untuk pencarian. Saya memilih untuk menggunakan Qdrant karena alasan yang sama kami memilih untuk menambahkan dukungan Qdrant native ke FiftyOne: itu adalah open source, gratis, dan mudah digunakan.
Untuk memulai dengan Qdrant, Anda dapat menarik gambar Docker yang telah dibuat sebelumnya dan menjalankan kontainer:
docker pull qdrant/qdrant
docker run -d -p 6333:6333 qdrant/qdrantSelain itu, Anda perlu menginstal klien Python Qdrant:
pip install qdrant-clientSaya membuat Qdrant Collection:
import qdrant_client as qc
import qdrant_client.http.models as qmodels
client = qc.QdrantClient(url="localhost")
METRIC = qmodels.Distance.DOT
DIMENSION = 1536
COLLECTION_NAME = "fiftyone_docs"
def create_index():
client.recreate_collection(
collection_name=COLLECTION_NAME,
vectors_config = qmodels.VectorParams(
size=DIMENSION,
distance=METRIC,
)
)Saya kemudian membuat sebuah vektor untuk setiap subbagian (blok teks atau kode):
import uuid
def create_subsection_vector(
subsection_content,
section_anchor,
page_url,
doc_type
):
vector = embed_text(subsection_content)
id = str(uuid.uuid1().int)[:32]
payload = {
"text": subsection_content,
"url": page_url,
"section_anchor": section_anchor,
"doc_type": doc_type,
"block_type": block_type
}
return id, vector, payloadUntuk setiap vektor, kamu dapat memberikan konteks tambahan sebagai bagian dari payload. Dalam hal ini, saya menyertakan URL (dan anchor) di mana hasilnya dapat ditemukan, jenis dokumen, sehingga pengguna dapat menentukan apakah mereka ingin mencari melalui semua dokumen atau hanya jenis dokumen tertentu, dan isi string yang dihasilkan vektor embedding. Saya juga menambahkan tipe blok (teks atau kode), sehingga jika pengguna mencari potongan kode, mereka dapat menyesuaikan pencarian mereka untuk tujuan tersebut.
Kemudian saya menambahkan vektor-vektor ini ke dalam indeks, satu halaman pada satu waktu:
def add_doc_to_index(subsections, page_url, doc_type, block_type):
ids = []
vectors = []
payloads = []
for section_anchor, section_content in subsections.items():
for subsection in section_content:
id, vector, payload = create_subsection_vector(
subsection,
section_anchor,
page_url,
doc_type,
block_type
)
ids.append(id)
vectors.append(vector)
payloads.append(payload)
## Add vectors to collection
client.upsert(
collection_name=COLLECTION_NAME,
points=qmodels.Batch(
ids = ids,
vectors=vectors,
payloads=payloads
),
)Cara Query index
Setelah index dibuat, pencarian pada dokumen yang telah diindeks dapat dilakukan dengan memasukkan teks pencarian ke dalam model embedding yang sama, dan mencari vektor embedding yang serupa pada index. Dengan sebuah index vektor Qdrant, pencarian dasar dapat dilakukan dengan perintah pencarian search() pada klien Qdrant.
Untuk membuat dokumen perusahaan saya dapat dicari, saya ingin memungkinkan pengguna untuk melakukan filter berdasarkan bagian dokumen, serta jenis blok yang dikodekan. Dalam bahasa pencarian vektor, penyaringan hasil sambil memastikan jumlah hasil tertentu (ditentukan oleh argumen top_k) akan dikembalikan disebut sebagai pre-filtering.
Untuk mencapai ini, saya menulis sebuah filter program:
def _generate_query_filter(query, doc_types, block_types):
"""Generates a filter for the query.
Args:
query: A string containing the query.
doc_types: A list of document types to search.
block_types: A list of block types to search.
Returns:
A filter for the query.
"""
doc_types = _parse_doc_types(doc_types)
block_types = _parse_block_types(block_types)
_filter = models.Filter(
must=[
models.Filter(
should= [
models.FieldCondition(
key="doc_type",
match=models.MatchValue(value=dt),
)
for dt in doc_types
],
),
models.Filter(
should= [
models.FieldCondition(
key="block_type",
match=models.MatchValue(value=bt),
)
for bt in block_types
]
)
]
)
return _filterSebuah program Python dibuat untuk memudahkan pencarian informasi pada dokumen-dokumen perusahaan. Program ini menggunakan model embedding OpenAI untuk menghasilkan vektor embedding pada setiap blok teks dan kode pada dokumen. Kemudian, program membangun sebuah indeks vektor dengan Qdrant, yang memungkinkan pengguna untuk melakukan pencarian dengan menggunakan metode vector similarity search.
Fungsi internal _parse_doc_types() dan _parse_block_types() menangani kasus di mana argumen memiliki nilai string atau daftar, atau bernilai None.
Selanjutnya, saya menulis fungsi query_index() yang mengambil kueri teks pengguna, melakukan pre-filtering, mencari indeks, dan mengekstrak informasi yang relevan dari muatan. Fungsi ini mengembalikan daftar tupel dalam bentuk (url, isi, skor), di mana skor menunjukkan seberapa baik hasil cocok dengan teks kueri.
def query_index(query, top_k=10, doc_types=None, block_types=None):
vector = embed_text(query)
_filter = _generate_query_filter(query, doc_types, block_types)
results = CLIENT.search(
collection_name=COLLECTION_NAME,
query_vector=vector,
query_filter=_filter,
limit=top_k,
with_payload=True,
search_params=_search_params,
)
results = [
(
f"{res.payload['url']}#{res.payload['section_anchor']}",
res.payload["text"],
res.score,
)
for res in results
]
return resultsPenelusuran Dokumen dengan Vector
Langkah terakhir adalah memberikan antarmuka yang bersih bagi pengguna untuk mencari secara semantis terhadap dokumen yang “vectorized”.
Saya menulis sebuah fungsi print_results(), yang mengambil kueri, hasil dari query_index(), dan argumen score (apakah atau tidak mencetak skor kesamaan), dan mencetak hasil dengan cara yang mudah dipahami. Saya menggunakan paket Python yang rich untuk memformat hyperlink di terminal sehingga saat bekerja di terminal yang mendukung hyperlink, mengklik hyperlink akan membuka halaman di browser default Anda. Saya juga menggunakan webbrowser untuk secara otomatis membuka tautan untuk hasil teratas, jika diinginkan.

Untuk pencarian berbasis Python, saya membuat kelas FiftyOneDocsSearch untuk mengelompokkan perilaku pencarian dokumen, sehingga setelah objek FiftyOneDocsSearch dibuat (mungkin dengan pengaturan standar untuk argumen pencarian):
from fiftyone.docs_search import FiftyOneDocsSearch
fosearch = FiftyOneDocsSearch(open_url=False, top_k=3, score=True)Anda dapat mencari di dalam Python dengan memanggil objek ini. Untuk mencari dokumen tentang “Bagaimana cara Meloading Dataset”, misalnya, Anda hanya perlu menjalankan:
fosearch(“How to load a dataset”)
Saya juga menggunakan argparse untuk membuat fungsionalitas pencarian dokumen ini tersedia melalui baris perintah. Saat paket diinstal, dokumen dapat dicari melalui CLI dengan:
fiftyone-docs-search query "<my-query>" <args Untuk sekadar iseng, karena kueri fiftyone-docs-search agak sulit, saya menambahkan alias ke file .zsrch saya:
alias fosearch='fiftyone-docs-search query'Dengan alias ini, dokumen dapat dicari melalui baris perintah dengan:
fosearch "<my-query>" argsKesimpulannya
Saat memulai proyek ini, saya sudah menganggap diri saya sebagai pengguna ahli dari pustaka Python open source perusahaan saya, FiftyOne. Saya telah menulis banyak dokumen, dan saya telah menggunakan (dan terus menggunakan) pustaka tersebut setiap hari. Tetapi proses mengubah dokumen kami menjadi basis data yang dapat dicari memaksa saya untuk memahami dokumen kami pada tingkat yang lebih dalam lagi. Selalu menyenangkan saat Anda membangun sesuatu untuk orang lain, dan akhirnya itu juga membantu Anda sendiri!
Inilah yang saya pelajari:
1. RST Sphinx kurang efisien: meskipun menghasilkan dokumen yang indah, tetapi cukup merepotkan untuk diproses.
2. Jangan terlalu khawatir dengan pra-pemrosesan: model text-embeddings-ada-002 dari OpenAI sangat bagus dalam memahami makna di balik rangkaian teks, bahkan jika formatnya sedikit tidak lazim. Kita tak perlu lagi menggunakan stemming dan menghapus stop word serta karakter-karakter tertentu dengan cermat.
3. Potongan teks kecil yang bermakna secara semantik adalah yang terbaik: pecahkan dokumen Anda menjadi segmen-segmen terkecil yang memiliki makna, dan pertahankan konteksnya. Pada teks yang lebih panjang, kemungkinan tumpang tindih antara kueri pencarian dan bagian teks dalam indeks Anda akan terhalang oleh teks yang kurang relevan di dalam segmen. Jika Anda memecah dokumen menjadi terlalu kecil, Anda berisiko bahwa banyak entri dalam indeks tidak mengandung informasi semantik yang banyak.
4. Pencarian vektor sangat powerful: dengan sedikit penyesuaian, dan tanpa penyetelan ulang, saya bisa secara dramatis meningkatkan kemampuan pencarian dokumen kami. Dari perkiraan awal, tampak bahwa pencarian dokumen yang diperbaiki ini lebih dari dua kali lebih mungkin mengembalikan hasil yang relevan daripada pendekatan pencarian kata kunci lama. Selain itu, sifat semantik dari pendekatan pencarian vektor ini berarti bahwa pengguna sekarang dapat mencari dengan kueri yang dirumuskan secara sembarang, secara sembarang kompleks, dan dijamin mendapatkan jumlah hasil yang ditentukan.
Jika Anda menemukan diri Anda (atau orang lain) terus-menerus menggali atau menyaring kumpulan dokumen untuk mencari informasi tertentu, saya mendorong Anda untuk menyesuaikan proses ini untuk kasus penggunaan Anda sendiri. Anda dapat memodifikasi ini untuk bekerja dengan dokumen pribadi Anda, atau arsip perusahaan Anda. Dan jika Anda melakukannya, saya jamin Anda akan berjalan menjauh dari pengalaman itu dengan melihat dokumen Anda dalam perspektif yang baru!
Berikut adalah beberapa cara di mana Anda dapat memperluas ini untuk dokumen Anda sendiri!
1. Hybrid Search: gabungkan pencarian vektor dengan pencarian kata kunci tradisional.
2. Go Global: Gunakan Qdrant Cloud untuk menyimpan dan memperoleh koleksi di cloud.
3. Gabungkan Data Web: gunakan request untuk mengunduh HTML
4. Pembaruan Automatisasi: gunakan Github Actions untuk memicu penghitungan kembali embedding setiap kali dokumen yang mendasarinya berubah
5. Embed: bungkus ini dalam elemen Javascript dan jadikan pengganti dari kotak pencarian tradisional
Semua kode yang digunakan untuk membangun paket ini adalah open source dan dapat ditemukan di repo voxel51/fiftyone-docs-search. Jika Anda sering mencari informasi di dokumen dan merasa kesulitan dalam mencarinya, saya mendorong Anda untuk mengadaptasi proses ini untuk keperluan Anda sendiri. Anda dapat memodifikasinya untuk bekerja dengan dokumen pribadi atau arsip perusahaan Anda. Dan jika Anda melakukannya, saya jamin Anda akan memandang dokumen Anda dengan sudut pandang yang baru!









