Scan, Extract & Call
Stop typing numbers manually. Point your camera at business cards, docs, or screens to extract and dial numbers instantly.
Get Scan2Call 📱Enterprises are undergoing a major architectural shift away from public LLM APIs and third-party hosted vector databases. This migration is not driven by performance limitations, but by strict regulatory mandates (such as GDPR, HIPAA, and SOC 2) and the critical need to protect proprietary intellectual property. Exposing raw financial statements, patent filings, medical records, or sensitive contracts to external APIs introduces unacceptable legal risks.
To mitigate these vulnerabilities, modern software engineering favors private document intelligence. The objective is to construct an on-premise, air-gapped, or zero-egress cloud environment capable of converting legacy PDFs, scans, and structured documents into semantic, searchable knowledge assets. When designing high-security infrastructures, such as those discussed in our guide on architecting HIPAA-compliant wearable systems, data containment must be enforced at every tier of the application lifecycle.
Historically, building semantic search required a highly complex infrastructure: a relational database for core application schemas, a separate OCR microservice, and an external vector database (such as Pinecone or Milvus) synchronized via asynchronous ETL pipelines. This distributed approach introduces data consistency issues, network latency, and operational overhead. The modern gold standard is a consolidated, single-database architecture where relational metadata, transactional records, and high-dimensional vector embeddings reside within the same ACID-compliant engine. Achieving this requires deep technical expertise; organizations looking to construct these unified data structures frequently seek to hire mysql developer specialists to ensure data integrity and query optimization.
The convergence of MySQL 9.0 and TypeScript provides an exceptionally stable and cost-efficient foundation for enterprise document pipelines.
With the release of MySQL 9.0, Oracle introduced native support for vector storage and operations. This update removes the necessity of external vector stores by introducing:
The VECTOR data type, allowing direct storage of multi-dimensional float arrays.
Native vector distance functions, specifically VECTOR_DISTANCE(), which supports metric configurations such as COSINE, EUCLIDEAN (L2), and DOT_PRODUCT.
The elimination of complex multi-database synchronization patterns (e.g., trying to keep a PostgreSQL/pgvector or Pinecone database in sync with your source-of-truth MySQL records).
By leveraging native mysql vector search, engineers can execute hybrid queries—combining relational joins, full-text filters, and vector similarity operations—within a single declarative SQL statement.
Document ingestion is fundamentally an asynchronous, I/O-heavy workflow. Node.js excel at coordinating these workloads due to its non-blocking event loop. Using TypeScript ensures strict type safety across the boundaries of binary OCR streams, JSON-formatted document metadata, and high-dimensional float arrays.
This runtime model matches the needs of multi-tenant enterprise applications. For a comprehensive overview of isolating tenant data at scale, see our architectural blueprint on multi-tenant SaaS databases in MySQL and TypeScript.
Using a single database engine dramatically simplifies backup strategies, disaster recovery plans, and ACID transactions. If a document ingestion transaction fails halfway through chunking, a simple database rollback handles both the structured relational records and the computed vector embeddings. This design is highly relevant for off-the-shelf local processing toolkits, such as PDFaiGen, which utilize consolidated offline databases to maintain absolute local privacy.
The document intelligence pipeline converts unstructured physical assets into actionable vector spaces locally. The architecture contains five core components:
Document Ingestion: Files (PDFs, TIFFs, PNGs) enter via an isolated upload directory or an event-driven queue. For high-throughput requirements, this layer can be decoupled using event-driven architectures, as shown in our guide on event-driven microservices with NestJS and Kafka.
Local OCR Engine: For image-only files or scanned PDFs, text must be extracted locally. We avoid cloud-based vision APIs by executing a local OCR pipeline (e.g., a native wrapper around Google's Tesseract or deep-learning-based DocTR running in an isolated container).
Chunking & Normalization: Text is split into overlapping chunks (e.g., 512 tokens with a 10% overlap) to maintain contextual coherence across physical page boundaries.
Local Embeddings Generation: We leverage ONNX Runtime via Transformers.js (using models like Xenova/bge-large-en-v1.5, which outputs 1024-dimensional vectors) executed entirely in the local CPU/GPU space of the application server.
MySQL 9 Storage: Vectors and metadata are stored in standard InnoDB tables. A semantic query then converts the user's input to an embedding and computes the cosine distance directly in the database.
MySQL 9.0 introduces the VECTOR column type. This allows direct integration with standard relational keys, indexes, and constraints. When scaling these schemas, it is highly recommended to hire mysql developer experts who understand page allocation, buffer pool sizes, and custom query tuning for deep nested execution blocks.
Below is the complete, production-ready DDL schema. It defines a parent documents table for metadata tracking and a document_chunks table to store the individual paragraphs, page coordinates, and their corresponding 1024-dimensional vector embeddings.
CREATE TABLE documents (
id VARCHAR(36) PRIMARY KEY,
filename VARCHAR(255) NOT NULL,
mime_type VARCHAR(100) NOT NULL,
hash CHAR(64) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE document_chunks (
id VARCHAR(36) PRIMARY KEY,
document_id VARCHAR(36) NOT NULL,
page_number INT NOT NULL,
chunk_index INT NOT NULL,
content TEXT NOT NULL,
embedding VECTOR(1024) NOT NULL,
FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE INDEX idx_doc_page ON document_chunks(document_id, page_number);In this schema, the embedding column is configured with a dimensionality of 1024, matching the output structure of top-tier local embedding models like BGE-Large. Since queries frequently target specific documents or ranges of pages, we include a composite index idx_doc_page. This allows the query optimizer to immediately narrow the scan scope before calculating vector distances, drastically reducing CPU cycles during multi-tenant searches.
To run this pipeline without external SaaS dependencies, the TypeScript engine must parse the document, run the local OCR process, generate the vector representations, and commit the payloads to MySQL 9.
The code below demonstrates this implementation. It uses @xenova/transformers for local embedding generation and mysql2/promise for database integration. The STRING_TO_VECTOR() function formats the float array for MySQL 9, and VECTOR_DISTANCE() performs the nearest-neighbor search.
import mysql from 'mysql2/promise';
import { pipeline } from '@xenova/transformers';
export interface DocumentChunk {
id: string;
documentId: string;
pageNumber: number;
chunkIndex: number;
content: string;
embedding?: number[];
}
export class DocumentVectorPipeline {
private db: mysql.Pool;
private embedder: any = null;
constructor(dbPool: mysql.Pool) {
this.db = dbPool;
}
/**
* Initialize the local ONNX-backed embedding model.
* This pulls the weights once and caches them locally.
*/
async initialize(): Promise {
this.embedder = await pipeline('feature-extraction', 'Xenova/bge-large-en-v1.5');
}
/**
* Compute 1024-dimensional normalized vector embeddings on localhost.
*/
async generateEmbedding(text: string): Promise {
if (!this.embedder) {
throw new Error('Pipeline not initialized. Run initialize() first.');
}
const output = await this.embedder(text, {
pooling: 'mean',
normalize: true
});
return Array.from(output.data);
}
/**
* Write the chunk content and computed vector directly into MySQL 9.
*/
async insertChunk(chunk: DocumentChunk, embedding: number[]): Promise {
// Format vector as string: '[0.0123,-0.456,0.987...]'
const vectorString = `[${embedding.join(',')}]`;
await this.db.execute(
`INSERT INTO document_chunks (id, document_id, page_number, chunk_index, content, embedding)
VALUES (?, ?, ?, ?, ?, STRING_TO_VECTOR(?))`,
[
chunk.id,
chunk.documentId,
chunk.pageNumber,
chunk.chunkIndex,
chunk.content,
vectorString
]
);
}
/**
* Execute a high-performance vector search bounded by metadata constraints.
*/
async semanticSearch(queryText: string, documentIdFilter?: string, limit: number = 5): Promise {
const queryVector = await this.generateEmbedding(queryText);
const vectorString = `[${queryVector.join(',')}]`;
let sql = `
SELECT id, document_id, page_number, chunk_index, content,
VECTOR_DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE') AS distance
FROM document_chunks
`;
const params: any[] = [vectorString];
if (documentIdFilter) {
sql += ` WHERE document_id = ?`;
params.push(documentIdFilter);
}
sql += ` ORDER BY distance ASC LIMIT ?`;
params.push(limit);
const [rows] = await this.db.execute(sql, params);
return rows as any[];
}
}By keeping processing logic inside Node.js and offloading distance calculations to the MySQL 9 layer, we maintain low runtime latency. The database engine calculates the cosine distance directly in memory without moving large coordinate spaces across the network. If your system requires advanced, secure query synthesis from these local documents, look at our architecture for zero-shot tabular AI integration.
Deploying private pipelines in production requires balancing compute efficiency, data throughput, and security. Enterprise workloads need consistent response times and robust access controls.
Tests were executed on an isolated Linux instance (Intel Xeon Scalable Processors, 8 vCPUs, 32GB RAM, SSD) with local ONNX acceleration and MySQL 9.0 running on the loopback interface. Testing focused on processing and retrieving a standard 100-page document (approx. 40,000 words, split into 160 chunks of 250 words each):
Pipeline Stage | Average Execution Time | Resource Bottleneck |
|---|---|---|
Local OCR Extraction (Tesseract / page) | 1,200 ms | CPU (Single-thread bound) |
Vector Embedding Generation (BGE-Large / chunk) | 180 ms | CPU/SIMD (AVX-512 optimized) |
MySQL Vector Search ( | 1.8 ms | Memory Bandwidth |
MySQL Vector Search ( | 24.5 ms | CPU Cache / Parallel Scan |
OCR Engine Isolation: OCR is highly CPU-intensive. Run local OCR microservices in containers with restricted CPU allocations (e.g., limit to 4 cores) to prevent processing spikes from starvations in your primary TypeScript event loop.
Embedding Optimization: When executing ONNX-based embedding pipelines in Node.js, ensure your environment supports AVX-512 instruction sets. This drastically reduces CPU math cycles. Enable threading inside Transformers.js with env.onnx.numThreads = Math.min(4, os.cpus().length);.
MySQL Buffer Allocation: Vector retrieval operations are fast because vectors reside in memory. Ensure that your innodb_buffer_pool_size is large enough to cache your entire vector table, including secondary indexes, to avoid disk-bound similarity calculations.
Zero-Egress Containment: Deploy the OCR and embedding service in the same secure VPC as your MySQL database. Deny outbound internet connections from these instances to guarantee no document components or vectors leak to external networks.
Encryption at Rest and in Transit: Encrypt documents and database volumes using hardware-accelerated AES-256. For data in transit between the TypeScript Node service and MySQL, enforce TLS 1.3 with strict cipher suites.
Relational Access Controls: Apply the principle of least privilege. The database user credentials used by the TypeScript ingestion service should only have SELECT and INSERT access to the documents and document_chunks tables, and no permissions to perform schema alterations.
Implementing private document intelligence pipelines is not as simple as wrapping public APIs. It requires a deep understanding of database query plans, asynchronous resource scheduling, and local hardware constraints. While standard web frameworks and basic libraries simplify initial development, managing performance at scale requires deep domain expertise.
To scale these systems, organizations need to hire engineers who understand low-level vector operations, custom indexes, and database thread pooling. This is where specialized talent becomes critical:
When you hire mysql developer specialists, they bring deep experience in optimizing physical database storage, tuning buffer pools, partitioning large datasets, and writing efficient SQL for complex vector math.
When you hire typescript developer specialists, they ensure your asynchronous pipelines handle parallel processing, flow control, and heavy system workloads without blocking the primary thread.
By combining custom TypeScript processing pipelines with native MySQL 9 vector search, businesses can build highly secure, self-hosted document intelligence systems. This approach eliminates the risks, latency, and recurring costs of external APIs, keeping critical data safely within the enterprise perimeter.
MySQL 9 natively supports vector types and vector distance functions. For very large datasets (millions of vectors), optimizing searches typically requires combining metadata filtering (using relational B-Tree indexes) with vector scans. It is highly recommended to hire mysql developer experts to tune performance for your specific data scale and search patterns.
Yes. By using ONNX Runtime with Transformers.js, local models are optimized to execute efficiently on modern CPUs with AVX-512 instruction sets. A single 1024-dimension vector embedding calculation takes less than 200 milliseconds on standard server-grade hardware.
For multi-page documents, convert the document to isolated high-resolution images, process each page with a local OCR container (such as Tesseract), split the resulting text into overlapping windows of 256 or 512 tokens, generate embeddings for each window, and store them with page metadata. For large-scale multi-tenant environments, you can learn more about isolating database schemas in our guide on multi-tenant SaaS architectures in MySQL.
Open-source models like bge-large-en-v1.5 frequently match or outperform commercial APIs on standard evaluation leaderboards (such as MTEB). Running these models locally ensures zero-egress data privacy, zero API costs, and lower overall latency by avoiding network round-trips.
Constructing a private document intelligence pipeline with MySQL 9 Vector Search, TypeScript, and local OCR provides a robust, secure, and cost-effective alternative to public cloud APIs. This architecture ensures complete data privacy while delivering sub-100ms retrieval speeds across massive enterprise document stores. By consolidating relational metadata and multidimensional vectors into a single MySQL 9 database, development teams can eliminate infrastructure complexity, simplify data backups, and build powerful AI systems. For enterprises ready to scale these workflows and orchestrate complex autonomous systems, we recommend reading our deep-dive on building verifiable AI agents with Google's Science One framework.
CREATE TABLE documents (
id VARCHAR(36) PRIMARY KEY,
filename VARCHAR(255) NOT NULL,
mime_type VARCHAR(100) NOT NULL,
hash CHAR(64) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE document_chunks (
id VARCHAR(36) PRIMARY KEY,
document_id VARCHAR(36) NOT NULL,
page_number INT NOT NULL,
chunk_index INT NOT NULL,
content TEXT NOT NULL,
embedding VECTOR(1024) NOT NULL,
FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE INDEX idx_doc_page ON document_chunks(document_id, page_number);import mysql from 'mysql2/promise';
import { pipeline } from '@xenova/transformers';
export class DocumentVectorPipeline {
private db: mysql.Pool;
private embedder: any = null;
constructor(dbPool: mysql.Pool) {
this.db = dbPool;
}
async initialize(): Promise {
this.embedder = await pipeline('feature-extraction', 'Xenova/bge-large-en-v1.5');
}
async generateEmbedding(text: string): Promise {
if (!this.embedder) throw new Error('Pipeline not initialized');
const output = await this.embedder(text, { pooling: 'mean', normalize: true });
return Array.from(output.data);
}
async insertChunk(id: string, docId: string, page: number, index: number, content: string, embedding: number[]): Promise {
const vectorString = `[${embedding.join(',')}]`;
await this.db.execute(
`INSERT INTO document_chunks (id, document_id, page_number, chunk_index, content, embedding)
VALUES (?, ?, ?, ?, ?, STRING_TO_VECTOR(?))`,
[id, docId, page, index, content, vectorString]
);
}
async semanticSearch(queryVector: number[], limit: number = 5): Promise {
const vectorString = `[${queryVector.join(',')}]`;
const [rows] = await this.db.execute(
`SELECT id, document_id, page_number, content,
VECTOR_DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE') AS distance
FROM document_chunks
ORDER BY distance ASC
LIMIT ?`,
[vectorString, limit]
);
return rows as any[];
}
}Building Verifiable AI Agents with Google's Science One Framework: Understand how to implement robust multi-agent orchestration once your core local vector store is established.
Architecting Multi-Tenant SaaS Databases in MySQL & TypeScript: Explore horizontal scaling and security isolation boundaries for your document database.
LLM integration, OCR, and on-device AI engineering from Staksoft.