Skip to main content
PreparationZone Logo
PrepZone

RAG across Files, the Web, Databases, and APIs

One retrieval pipeline, many loaders: PDF, text, CSV, URLs, SQL, and REST, then one vector index.

Pass checkpoint below

Why this matters

  • PolicyDesk's handbook lived in PDF, the holiday calendar in a sheet, and branch addresses on the intranet. Three loaders, one index.
  • Interviewers ask "how would you ingest a database?" to see if you turn rows into text on purpose instead of embedding raw tuples blindly.
  • Access control is a source problem. A row the user cannot see must not become a chunk they can retrieve.
  • Refresh schedules differ. A policy PDF changes monthly. A rate API changes daily. One cron for everything will be wrong.

One pipeline, many front doors

Sources PolicyDesk actually has

  • Local files: PDF, TXT, DOCX, CSV, and spreadsheets on a drive or in object storage.
  • Web pages: the public FAQ and the intranet help center, fetched by URL.
  • Databases: Postgres for structured policy tables, sometimes Mongo for form submissions.
  • APIs: REST endpoints that already speak JSON, including HR systems you do not get a database login for.
  • Object storage: S3 or similar for the nightly handbook drop.
  • Unstructured dumps: HTML, scanned images, and email. These need extraction, not a naive text split.

Each source becomes documents with page_content and metadata. After that, chunk, embed, and upsert are shared. Do not build a second vector collection per format unless the embedding model or the access domain truly differs.

Loaders, one by one

PDF. PyPDFLoader reads a digital text layer. It will return empty pages for a scan. For scans, OCR first. For multi-column layouts and tables, use a parser that understands layout (the tables lesson). Always keep page number in metadata.

Java
from langchain_community.document_loaders import PyPDFLoader

pages = PyPDFLoader("leave-policy.pdf").load()
print(len(pages), pages[0].metadata.get("page"))

Plain text. TextLoader is enough for markdown and .txt. You still chunk, because a whole wiki export is not one retrieval unit.

CSV and Excel. Each row should become text a human would say, not a comma salad.

Java
from langchain_community.document_loaders import CSVLoader

rows = CSVLoader("holiday-calendar.csv").load()

Prefer a template: "Holiday: Republic Day. Date: 26 January. Offices: all India." Embed that sentence. Keep the date and region as metadata so you can filter "Mumbai office" without hoping the vector notices a column. Spreadsheet loaders (UnstructuredExcelLoader and its cousins) exist for xlsx. Merged cells and multiple sheets still need a look with your eyes.

Web. WebBaseLoader fetches a URL. Strip navigation, cookie banners, and footers before chunking, or every page looks like the site chrome.

Java
from langchain_community.document_loaders import WebBaseLoader

docs = WebBaseLoader("https://intranet.northline.example/holidays").load()

Respect robots, auth, and copyright. An internal crawler with a service account is not a license to index the public internet. Record the URL and the fetch time in metadata so you can expire stale pages.

SQL. Select the columns that belong in the answer. Do not SELECT * from a table of national IDs and embed it.

Java
from langchain_community.utilities import SQLDatabase

db = SQLDatabase.from_uri("postgresql://policy_reader@db/hr")
# Prefer an explicit query that projects safe columns only.
rows = db.run("SELECT name, days, eligibility FROM leave_rules")

Turn each row into a short document, with the primary key in metadata so an update can delete the old point. A database is also a candidate for not using vectors: if the question is "how many days is casual leave?" and the value is a column, a SQL query is the accurate tool. Vectors are for fuzzy wording over text. The text-to-SQL project in the next lesson is that other tool. Use both when the product has both fuzzy policy prose and exact tables.

APIs. Call the endpoint, keep only the fields you will show, and shape them into text plus metadata.

Java
import requests

payload = requests.get(
    "https://hr.internal.example/policies/leave",
    timeout=10,
).json()
text = payload["summary"]
metadata = {"source": "leave-api", "version": payload["version"]}

Paginate. Time out. Do not embed error bodies ({"error": "unauthorized"}) or you will retrieve them forever.

The rest of this guide is part of Pro

Free covers every fresher guide in full. Pro unlocks Senior, Staff and Architect guides across every track.

Still to come · 3 sections

  • Many sources, one collection
  • A combined indexing sketch
  • Practices per source

Test yourself

Answer these before moving on — recall is what makes it stick.