Can a user retrieve information outside their permissions, including through the lexical search path, caches, or indirect references?
Jeevan Srivastava asked this question word for word in a Medium article of 18 October 2026, as one of three dimensions he would assess for a production system, beside retrieval quality and operational performance. He labels his access-control design: "These are proposed production design decisions, not features I'm claiming to have implemented as part of my retrieval fix."
> TL;DR
>
> - Yes, through any read path the permission check does not cover. The question names three: the lexical branch of a hybrid search, filtered differently from the vector branch; a cache that answers before the check runs; and indirect references, such as a fetch by ID or exact name, a pointer to a hidden record, or a scope value supplied by the request or the model.
> - One rule addresses all three: the server derives the read scope from the verified caller identity and applies one filter on every path that can return stored content. For the model's part, the Databricks agent memory documentation says of the actor_id that scopes every read: "Never let the model choose it."
> - Three probes, run as a user without access, test whether a system holds: a rare word from a restricted document through every search branch; a cache warmed by a user with access; and a direct fetch, a followed pointer and a foreign scope. Each needs a positive control run as a user with access, or an empty result proves nothing.
Mnemoverse (the author's company) makes one of the memory APIs quoted below.
Can a user retrieve information outside their permissions?
Yes, whenever a path that returns stored content skips the check that search runs.
A read path is any function, endpoint or query type that can return stored content to a caller: a search, an exact get, a list, an export, an admin surface or a debug endpoint. Heinrich Neb, who works on a memory layer for coding agents, gave the audit rule in a dev.to comment of 27 August 2026: "find every function that can return stored content."
| Read path | How it returns what the user may not see | What closes it | Documented by |
|---|---|---|---|
| Lexical branch of a hybrid search | The full-text query lacks the vector query's filter | One filter below both branches, or passed to each | Srivastava; PostgreSQL; Elasticsearch |
| Cache in front of retrieval | A stored answer is served before the check | The caller's scope in the key, or the cache behind the check | RFC 9111, for shared HTTP caches |
| Fetch by ID or exact name | A lookup outside search returns the record | An object-level check on every route that takes an ID or a name | OWASP API1:2023; Neb |
| Pointer from a visible record | A visible record names a hidden one | The target's visibility checked when the pointer is read | Neb; PostgreSQL |
| Scope from the request or the model | A user ID or tag from the path, body or a tool argument is trusted | Scope from the verified identity; supplied values checked against the configured set | Databricks; Supermemory; Mem0; Anis Meziani |
| Query language as a search type | Raw queries reach the store | Off unless every user of the deployment is trusted | Cognee |
The last four rows are kinds of indirect reference. Srivastava separates the two decisions: "Relevance determines whether information is useful. Authorization determines whether information is allowed to be accessed."
How does the lexical search path leak in a hybrid search?
The lexical branch is the half of a hybrid search that matches the query's words against a full-text index, such as BM25 or PostgreSQL full-text search, beside the vector half that matches embeddings.
Srivastava's rule: "The key decision is that both vector search and lexical search must respect the same access restrictions." The failure: "If vector search filters by tenant or document permissions but PostgreSQL full-text search doesn't, the hybrid retrieval pipeline can introduce a data leak through the lexical branch." On merging the two lists: "Combining rankings must never override authorization boundaries." And at retrieval time: "Apply authorization and tenant filters to every retrieval path."
One filter can reach both branches from two places.
Below both branches, in the database. With row security enabled on a PostgreSQL table, "all normal access to the table for selecting rows or modifying rows must be allowed by a row security policy", and a table with no policy falls back to "a default-deny policy" (PostgreSQL, Row Security Policies). The same page sets two limits: "the table's owner is typically not subject to row security policies" unless the table is altered with FORCE ROW LEVEL SECURITY, and "Superusers and roles with the BYPASSRLS attribute always bypass the row security system when accessing a table." An application that connects as the owner of an unforced table, as a superuser or as a BYPASSRLS role is not filtered at all.
One filter passed to every branch. The filter parameter of the Elasticsearch RRF retriever "Applies the specified boolean query filter to all of the specified sub-retrievers, according to each retriever's specifications." Written once, it cannot drift between two copies.
OWASP's LLM08:2025 opens its prevention list with: "Implement fine-grained access controls and permission-aware vector and embedding stores." The OWASP text speaks of vector and embedding stores; a hybrid pipeline has a second index, and the same rule has to reach it. Srivastava adds a condition that holds over time: "metadata can become stale if permissions change and the retrieval index isn't updated accordingly."
Does a permission filter keep a restricted user's results complete?
Nothing leaks here; the risk runs the other way. The pgvector README: "With approximate indexes, filtering is applied after the index is scanned. If a condition matches 10% of rows, with HNSW and the default hnsw.ef_search of 40, only 4 rows will match on average." Its first suggestion, an index on the filter column, can give exact search in many cases, so the shortfall applies whenever the planner takes the HNSW index instead.
What follows is this article's inference for a vector branch on pgvector with an HNSW index, not a measurement. A permission rule is a condition that keeps some share of the rows, so the narrower a user's rights, the fewer rows one scan of the vector index can return, while the full-text branch can still return every permitted match. For hybrid search the README offers fusion: "You can use Reciprocal Rank Fusion or a cross-encoder to combine results." Fusion ranks the lists it receives, so a restricted user's top results draw more on keyword matches than an administrator's do. An evaluation run as an administrator measures only the administrator's ranking: report retrieval quality per permission level.
The README's levers: "Starting with 0.8.0, you can enable iterative index scans, which will automatically scan more of the index until enough results are found". On tenants: "For applications with multiple tenants, sharing an approximate index between tenants means vectors from one tenant can affect recall (and speed) for other tenants." And: "For tenant isolation, use list partitioning or separate tables."
Can a cache answer with documents the user may not see?
Yes, when it answers before the check runs. For shared HTTP caches, RFC 9111, section 3.5, sets the rule: "A shared cache MUST NOT use a cached response to a request with an Authorization header field" to satisfy a later request, unless the response allows shared storage through a Cache-Control directive such as public, s-maxage or must-revalidate. A semantic or answer cache inside an application follows whatever rule the application gives it.
Naveen Metta, in an article of 12 October 2026 on RAG before production, states the requirement:
> If a user cannot open the document, the model should not be able to quote it.
From his team's work: "We found one prompt that could surface HR documents to any employee." He also advises: "Then add a semantic cache in Redis for repeated questions." This article's inference about any cache in front of retrieval, not a description of his system: such a cache answers without running the filter, so the caller's scope has to be part of what it matches on, or it has to sit behind the check.
Srivastava would test "whether permissions and deletion requests propagate to the relevant indexed and cached data." The warm, revoke, replay test is covered in the library page on revoked access after an answer was shown, and caches after a delete in Agent Memory Deletion: What Survives a Delete.
What counts as an indirect reference, and how does it leak?
An indirect reference is any way to reach a record other than a search the filter covers: its ID, its exact name, a pointer from another record, a scope value or a query language.
An existence leak is an answer that reveals that a hidden record exists, or something about it, without returning its content.
The fetch that skips search. Neb, on his own system: "We had scoping enforced correctly on retrieval, tested, verified", and beside it "a second read path, lookup by exact name rather than similarity, that returned full content to anyone who asked." In short: "Same store, two doors, one guarded." The sign in code: "a read path that doesn't accept the caller identity cannot enforce anything". For APIs, OWASP API1:2023 Broken Object Level Authorization: "Every API endpoint that receives an ID of an object, and performs any action on the object, should implement object-level authorization checks."
The pointer. On 25 August 2026, Neb reported a retired record whose banner kept naming its successor after the successor was made private: "Existence leak through the supersession pointer." His rule: "a pointer's validity and a pointer's visibility are both read-time questions, never write-time facts." PostgreSQL warns of a related channel: its referential integrity checks always bypass row security, and "Care must be taken when developing schemas and row level policies to avoid "covert channel" leaks of information through such referential integrity checks."
The query language. Cognee pull request #5844, merged into its dev branch on 15 October 2026: "CYPHER and NATURAL_LANGUAGE search types run raw Cypher against the graph database." And: "Any user with read access to a dataset could execute arbitrary queries". The change: "ALLOW_CYPHER_QUERY now defaults to false." For turning it back on: "Only do that when every user of the deployment is trusted."
What closes the class: a check at every entry point, and a refusal that neither names nor describes the hidden record, so that a missing record and someone else's record get the same answer. An answer that tells the two apart reveals existence, which is acceptable only where existence is not a secret.
Who should set the scope of a memory read: the server, the request or the model?
A caller-supplied scope is a value that selects whose data a read covers, such as a user ID, a tenant tag or an actor ID, and that arrives with the request or from the model instead of from the verified identity.
The Databricks agent memory documentation (Beta, last updated 26 October 2026) states the rule: "Set actor_id in your application code from trusted caller context: the verified end-user identity for per-user memory, or a trusted team or project key for shared memory. Never let the model choose it." And: "If your strategy depends on an end-user identity, reject requests that don't carry one rather than falling back to a shared actor_id."
Three classes of the error, each with a dated fix:
A scope chosen by the model. Supermemory pull request #1824, merged on 16 October 2026 into the 2.x release branch of its tools package: "In 2.x, getProfile, documentList, memoryForget and documentDelete accept an optional containerTag from the model and use it unchecked as the request scope." The consequence: "So a model, or a prompt-injected input, can name another tenant's tag and read their profile, list their documents, forget their memories, or delete their documents." The fix: "A model-supplied tag must be one of the tags the developer configured", or the call fails "before any request is sent". The pull request also notes: "Tools 3.x (#1773) already removed model-selected scope."
An empty scope read as everything. Mem0 pull request #7581, merged on 12 October 2026, on its hosted clients: "The dangerous one is an empty entity ID. The API treats an empty ID as matching every memory in the project." The case there is the delete calls, delete_all and delete_users, fixed on the client: "This PR blocks that client-side. The server needs its own fix, which is out of scope here." This article did not check whether the server has changed since.
A scope taken from the path or the body. Anis Meziani, replying on 14 October 2026 to a comment under his own dev.to article: "Our ADK-native session routes originally checked that a token was valid, not which user it acted for, so the user_id in the path or body was trusted." His fix checks the token's subject against the user_id "on every route that reads sessions or memory, including the live WebSocket".
The rule: the scope comes from the verified identity; a request without one is refused, not given a shared scope; an empty value is an error, not everything; a value from the model is checked against the configured set before any request goes out.
What changes when several users share one memory store?
In a shared store the question moves from the answer to the context. A preprint of 19 October 2026 (arXiv 2610.25707, version 1, not peer-reviewed) opens: "Shared long-term memory lets an LLM agent serving one user inadvertently retrieve another user's credentials, but it is unclear when such exposure leads to actual harm." Its audit used the AppWorld environment and one store for all users' logins: "In AppWorld, a store that mixes 763 past logins from all users retrieves another user's credential for 84.7 percent of required apps, yet agents rarely act on it." Of the misuse its stress test provokes: "Naming the owner before or inside each credential line prevents most of this". Its conclusion: "Agent memory should consistently record whose credential it stores, and evaluations should measure behavior, not only exposure."
This article's reading: the boundary is crossed when another user's record reaches the model's context, whether or not the model uses it. Srivastava, from the design side: "The stronger approach is to prevent unauthorized information from entering the context in the first place."
Databricks states where the boundary sits: "actor_id separates memories, but it is not an access control. Memory stores are workspace-scoped, so any principal that can reach a store can read and write every entry across all actors." And: "The store, not the actor, is the security boundary. For strict isolation between tenants or users, create a separate memory store per boundary." OWASP's LLM08:2025, for vector databases: "In multi-tenant environments where multiple classes of users or applications share the same vector database, there's a risk of context leakage between users or queries."
How do you test that no read path leaks?
Each probe has a positive control, because a probe that finds nothing proves nothing until it finds something where it should. They are this article's proposals, not any team's suite.
1. The lexical branch. As the test user, run vector-only, lexical-only and hybrid queries for a rare word, such as a code name, found only in a document the user may not open. Expected: no chunk of it. Control: a user with access gets it. Srivastava proposes this negative test: "Queries from unauthorized users should not expose protected documents, even when those documents are semantically similar to the query."
2. The cache. User A, with access, asks a question whose answer needs the restricted document; user B, without access, asks it and a paraphrase. Expected: B's answer is not built from that document. Control: A's answer is built from that document, and B's answer with the cache off matches B's answer with the cache on.
3. Indirect references. As a user without access, fetch the record by ID and by exact name, follow a pointer to it from a visible record, and send another user's scope and an empty scope. Expected: the same answer as for a record that does not exist. Controls: as a user with access, the same fetch, pointer and scope return the record, so the path is live; a made-up ID on the same path gives the answer to compare against.
Three rules for the run:
- Take the list of read paths from the code or the tool registry, not from a filtered listing. sam ros, on 15 October 2026, about the CI test of the scope check in his MCP server: "with a list_tools override that filters by the token's scopes, the old test passed while a tickets:read token could still delete."
- Rerun the probes after a permission change and after a delete: permission data copied into an index or a cache can go stale.
- Inspect what reached the model's context, not only the final answer.
A passing first probe says nothing about the second and the third.
How do memory APIs document where the boundary is?
Two documented positions, in their own words, as read on 2 November 2026.
Databricks. The store is the boundary, and application code, not the model, sets the actor ID; both are quoted above.
Mnemoverse. The security page states the tenant boundary: "Every API key is bound to a unique organization_id. All database queries are scoped to your organization." Shared rooms (beta) stay apart: "room content never appears in your normal (non-room) searches". The rooms reference covers indirect references: "Knowing a room id grants no access to its contents: access is enforced by the API's membership check on every request, and non-members get 403." And: "Membership is checked before archive state, so a non-member of an archived room still gets the membership 403", so the answer does not reveal whether a room is archived. This is a documented boundary, not a test result; this article tests no product.
What this article does not claim
No measurement of any product and no figure for how often any system leaks. The numbers above are the pgvector README's illustration and one preprint's audit, each with its conditions. Vendor fixes are quoted from their own pull requests with their merge dates; this article did not check whether a fix has reached a release. The inference about rank fusion is for pgvector with an HNSW index and was not measured. The probes are proposals, not a description of any team's suite.
---
Sources and method. Every quotation was read on 2 November 2026 with two instruments, a browser-like request and a second reading of the same text: a reader service with its cache off, and in addition the dev.to API for the dev.to comments, the RSS feed for Jeevan Srivastava's article and the arXiv API for the preprint; for the GitHub pull requests and the pgvector README, which the reader service refuses, the GitHub API and the raw file took its place. A made-up address on each host answered 404 as a control, except Medium, which answers 200 to any address, so there only the article text counts. The text describes those pages as of that date. A longer version, with the common questions and the full list of sources, is in the Mnemoverse documentation library: Can a user retrieve information outside their permissions, including through the lexical search path, caches, or indirect references?
Edward Izgorodin · Mnemoverse · 2026-11-02
Four Bounded Semantic Retrieval Paths for Healthcare Appointment Assistants
Collection queries timing out in a healthcare appointment assistant are usually a contract problem before they are a vector-database problem. Short answer: use staged retrieval with explicit collections, bounded queries, and source context that can be traced back to a document. That gives the assistant a useful fallback when a specialist index is slow, without silently turning a scheduling answer into a guess.
The flow I want is small enough to reason about: classify the appointment request, query the narrow collection first, stop at a deadline, then try a broader or lexical source, and finally ask for clarification or hand off. Every result carries a URL or document ID. The answer renderer never receives anonymous chunks.
What should semantic retrieval return for a healthcare appointment assistant?
Start with a retrieval contract, not a vendor SDK. For an intent such as “find a follow-up with Dr. Lee next week,” the contract can require a specialty, location, date window, and evidence fields. A hit that lacks its source identifier is incomplete even when its similarity score is high.
Here is a compact TypeScript runner. The adapters are deliberately boring: they make the timeout and fallback policy visible, and they are easy to replace with Pinecone, Weaviate, pgvector, or an HTTP service. The first adapter below uses Infrai's plain REST surface, so the same request pattern works from a small worker without installing a client library.
type Hit = {
text: string;
score: number;
sourceUrl?: string;
documentId: string;
};
type Retriever = (query: string, signal: AbortSignal) => Promise<Hit[]>;
async function queryInfrai(collection: string, query: string, signal: AbortSignal): Promise<Hit[]> {
const key = process.env.INFRAI_API_KEY;
if (!key) throw new Error("INFRAI_API_KEY is required");
for (let attempt = 0; attempt < 3; attempt += 1) {
const apiHost = ["api", "infrai", "cc"].join(".");
const response = await fetch(`https://${apiHost}/v1/vector/query`, {
method: "POST",
signal,
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ collection, query, top_k: 5 }),
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after") ?? "1");
await new Promise((resolve) => setTimeout(resolve, Math.min(retryAfter * 1000, 4000) * (attempt + 1)));
continue;
}
if (!response.ok) throw new Error(`retrieval failed: ${response.status} ${await response.text()}`);
const payload = (await response.json()) as { hits?: Hit[] };
return payload.hits ?? [];
}
throw new Error("retrieval rate limit persisted");
}
async function withDeadline<T>(work: (signal: AbortSignal) => Promise<T>, ms: number): Promise<T> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), ms);
try {
return await work(controller.signal);
} finally {
clearTimeout(timer);
}
}
async function retrieveWithFallback(query: string, retrievers: Retriever[]): Promise<Hit[]> {
const budgets = [180, 260, 360];
for (let i = 0; i < retrievers.length; i += 1) {
try {
const hits = await withDeadline(
(signal) => retrievers[i](query, signal),
budgets[i] ?? 400,
);
const traceable = hits.filter((hit) => hit.documentId && (hit.sourceUrl || hit.documentId));
if (traceable.length > 0) return traceable.slice(0, 5);
} catch (error) {
if (!(error instanceof DOMException) || error.name !== "AbortError") throw error;
}
}
return [];
}
The first adapter should target a collection containing current clinic schedules and policy documents. The second can search a broader appointment collection; the third can be a deterministic lookup for provider, clinic, or opening identifiers. The limits are intentional. A slow source cannot hold the user-facing request indefinitely, and returning five traceable hits is more useful than returning fifty opaque fragments.
One production trap is retrying every failure in the same tier. That multiplies load while the user waits. Retry once only for a transient transport failure, pass the remaining budget to the next tier, and record which tier answered. I once treated a timeout as permission to widen the query immediately; the result looked plausible but mixed pediatric and adult clinics. Narrow-first is slower only when it fails, and the trace tells you why.
How do fallback stages balance retrieval quality and latency?
Use four stages, each with a clear exit condition:
1. Exact constraints: filter by specialty, site, and date window before semantic ranking. This protects clinical relevance.
2. Narrow semantic search: query the current-schedule collection with a small top-k and a short deadline.
3. Broader evidence search: include approved policy and FAQ collections when the narrow tier has no traceable hit.
4. Safe handoff: ask one clarifying question or route to staff when evidence is empty or contradictory.
Quality is not just the similarity score. Check that dates are in the requested window, the provider is active, and every claim can be cited. Latency is not just the database timer either; embedding, network, reranking, and answer generation all consume the same user budget. Set one request deadline and allocate smaller budgets inside it.
Keep it bounded.
No guesswork.
For a useful incident record, store the original intent fields beside the query text, the collection version, each adapter's start and end timestamp, the timeout reason, and the exact source IDs selected for generation. That record lets you distinguish a bad embedding from an expired schedule, and it gives a reviewer enough context to reproduce a response without copying sensitive patient text into a ticket.
The longest part of this work is usually the test matrix. Take one request for a cardiology follow-up, then vary only one dimension at a time: the schedule document is current or stale, the provider is present or deleted, the narrow collection responds within 180 ms or exceeds its budget, and the broader policy collection has either a matching rule or none. For each case, assert the tier chosen, the number of returned sources, and whether the answer is allowed to proceed. This catches a subtle failure mode where a fallback returns a semantically similar policy paragraph but no appointment availability; the assistant must ask a question instead of blending those facts into a confident slot recommendation. I am not sure every team needs four physical indexes, but every team needs four explicit outcomes, because “some context came back” is not a safe contract.
When content changes, re-index deliberately. Upsert the new version, retain its document ID and source URL, then remove deleted records from the collection. A stale appointment slot is a correctness failure, not a harmless cache miss. Keep an index version in your trace so an incident review can reproduce what the assistant saw.
Which retrieval option fits this fallback design?
The right choice depends on your operational boundary, not a leaderboard. Pinecone is convenient when you want a managed vector service and are comfortable with its hosted indexing model. Weaviate offers a broad open-source and managed surface with schema features. pgvector is a strong fit when Postgres is already the system of record and SQL filters matter more than a separate service.
| Option | Useful strength | Trade-off for this workflow |
| --- | --- | --- |
| Pinecone | Managed vector operations | Another hosted dependency and filtering model to operate |
| Weaviate | Flexible schema and deployment choices | More surface area to configure and monitor |
| pgvector | SQL joins and transactional data nearby | You own tuning, scaling, and vector maintenance |
| A plain HTTP aggregation layer | One contract across providers | You still need to design ranking, traces, and failure policy |
Infrai can be the HTTP aggregation layer when a solo team wants one REST API, one key, and no SDK installation while keeping provider changes behind an adapter. That is an integration advantage, not proof of better retrieval quality; you still need to measure recall and tail latency on your own appointment corpus.
The catch is real: this design is not suitable when you need specialized vector indexing controls, on-premise data residency guarantees, or a vendor-specific feature that the adapter cannot expose. Stick with pgvector when appointment records must join transactionally with scheduling tables. Choose Pinecone or Weaviate when their managed operations reduce work your team does not want to own.
An operational checklist that survives the first incident
Log the query class, collection, deadline, tier, result count, document IDs, and final answer citations. Redact patient details before those traces leave the protected environment. Alert on empty-evidence answers and on repeated deadline exhaustion, not only on HTTP errors.
Test the fallback path with deliberately slow adapters, deleted documents, stale schedules, and ambiguous provider names. Verify that a timeout moves to the next bounded tier, that a missing source blocks an uncited answer, and that a retry cannot duplicate an indexing write. Your mileage may vary across regions and corpus sizes; the contract is what keeps that variation visible.
References
- arxiv.org
- docs.pinecone.io
- weaviate.io
- pgvector/pgvector
pgvector ⭐ 24k
pgvector adds vector similarity search to Postgres, for developers building search and recommendation features.
🔗 pgvector/pgvector
#opensource t.co
3 views
@ArdenBuilds i am trying out pg vector. pgvector/pgvector
1 like · 14 views
pgvectorの各機能の実機検証!
はじめに
以前書いた「pgvectorで学ぶVector Database(RAGの基礎)」の続きです。
もしVector Databaseの概要を知らなければ、そちらの記事の図を見ていただければなんとなくわかると思います。
また、記事に出てくる用語は「補足」章にまとめています。必要であれば参照してください。
前回の記事では、20件の英語のサンプル文を入れてベクトル検索を動かしてみたのですが、最後のおまけでIVFFlatインデックスを貼って検索したときに、インデックスを貼る前とコサイン距離の数値も順位もまったく同じになる、という結果になっていました。
近似検索なのに結果が変わらないのはデータ件数が少なすぎたからとArgonさんに回答を頂いたので、その他機能とともに検証します。今回は日本語の文章データを3,000件入れて、psqlでログインして各機能を手で動かしながら試してみました。
検証に使ったファイル等はこちらにおいてます:hsmto25519/pgvector-test
今回の検証の前提
検証に入る前に、データの作り方についていくつか前提を置いておきます。
まず、実際にドキュメントなどを対象にRAGを組む場合は、長い文章を適切な長さに分割する処理が必要になりますが、今回はpgvector自体の動きを見ることが目的なので、分割処理は省略して最初から1文ずつに分かれた日本語の文章がある前提で進めます。
また、テーブルへ入れる日本語の文章については、社内規定やIT運用のマニュアルを想定した20カテゴリ・3,000件のセンテンスをAIに出力してもらい、1つのJSONファイル(sentences_3000.json)に用意して使っています。
検証準備
環境確認
前回と同じく、WSL2(Ubuntu 24.04)上のDockerとPythonを使います。
まずはWSL上の環境を確認しておきます。
lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.1 LTS
Release: 24.04
Codename: noble
docker --version
Docker version 29.1.3, build 29.1.3-0ubuntu3~24.04.2
python3 --version
Python 3.12.3
DockerコンテナはPostgreSQL 18ベースの pgvector/pgvector:pg18 を使います。
services:
db:
image: pgvector/pgvector:pg18
container_name: pgvector_pg18_test
ports:
- "127.0.0.1:5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret0001
POSTGRES_DB: vector_db
volumes:
- pgdata:/var/lib/postgresql
volumes:
pgdata:
コンテナを起動して psql でログインし、バージョンと vector 拡張を確認します。PostgreSQL 18.6、pgvectorは 0.8.7 (現時点の最新版) が入っています。
docker exec -it pgvector_pg18_test psql -U postgres -d vector_db
psql (18.6 (Debian 18.6-1.pgdg12+2))
Type "help" for help.
vector_db=# CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION
vector_db=# \dx
List of installed extensions
Name | Version | Schema | Description
---------+---------+------------+------------------------------------------------------
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
vector | 0.8.7 | public | vector data type and ivfflat and hnsw access methods
(2 rows)
データ投入(Python)
3,000件のデータを手で入れるのは大変なので、データを入れるところだけPython(insert_data.py)で自動化します。
今回は sentences_3000.json に用意した3,000件の日本語文章を読み込み、Embeddingモデルを使ってベクトル化してからPostgreSQLへ投入します。初回実行時はモデルのダウンロードが走るためトータルで1分前後かかります。
- 利用Embeddingモデル: intfloat/multilingual-e5-small(384次元)
- モデル容量約500MB
また、あとでpsqlにログインして手動でSQLを実行するときに384次元の長い配列を毎回貼らなくて済むよう、検索クエリ用の文章(PostgreSQLのインデックスを使ってベクトル検索を高速化する方法)とそのベクトルを query_target という別テーブルに1件保存しています。
なお、multilingual-e5系のモデルは検索対象の文章に "passage: "、検索クエリに "query: " というプレフィックスを付けてベクトル化する仕様になっているため、コード内でもそれを付けて変換しています。
import json
import psycopg2
from psycopg2.extras import execute_values
from sentence_transformers import SentenceTransformer
MODEL_NAME = "intfloat/multilingual-e5-small"
# 1. 事前に用意した3,000件の日本語文章データを読み込む
with open("sentences_3000.json", "r", encoding="utf-8") as f:
data = json.load(f)
# 2. Embeddingモデルで3,000件の文章をベクトル化(E5モデルの仕様に合わせて "passage: " を付与)
model = SentenceTransformer(MODEL_NAME)
passages = ["passage: " + item["sentence"] for item in data]
embeddings = model.encode(passages, batch_size=128, show_progress_bar=True)
# 3. PostgreSQLへ接続してテーブル作成・データ投入
conn = psycopg2.connect(
host="localhost",
port=5432,
database="vector_db",
user="postgres",
password="secret0001",
)
conn.autocommit = True
cursor = conn.cursor()
cursor.execute("CREATE EXTENSION IF NOT EXISTS vector;")
cursor.execute("DROP TABLE IF EXISTS items;")
cursor.execute("""
CREATE TABLE items (
id SERIAL PRIMARY KEY,
category TEXT,
sentence TEXT,
embedding VECTOR(384)
);
""")
rows = []
for item, emb in zip(data, embeddings):
vec_str = "[" + ",".join(f"{float(v):.6f}" for v in emb) + "]"
rows.append((item["category"], item["sentence"], vec_str))
execute_values(
cursor,
"INSERT INTO items (category, sentence, embedding) VALUES %s",
rows,
)
cursor.execute("ANALYZE items;")
# 4. 検索用のクエリ文とベクトルを別テーブルに1件保存(検索クエリには "query: " を付与)
query_text = "PostgreSQLのインデックスを使ってベクトル検索を高速化する方法"
query_emb = model.encode("query: " + query_text)
query_vec = "[" + ",".join(f"{float(v):.6f}" for v in query_emb) + "]"
cursor.execute("DROP TABLE IF EXISTS query_target;")
cursor.execute("""
CREATE TABLE query_target (
q_text TEXT,
q_vec VECTOR(384)
);
""")
cursor.execute(
"INSERT INTO query_target VALUES (%s, %s::vector);",
(query_text, query_vec),
)
cursor.execute("ANALYZE query_target;")
cursor.close()
conn.close()
print("done")
スクリプトを実行してデータを入れます。
python insert_data.py
Batches: 100%|██████████████████████████████████████████| 24/24 [00:35<00:00, 1.47s/it]
done
データが入ったので、ここからはpsqlでPostgresにログインして手動でコマンドを実行していきます。
docker exec -it pgvector_pg18_test psql -U postgres -d vector_db
vector_db=# SELECT id, category, sentence FROM items WHERE id <= 5 ORDER BY id;
id | category | sentence
----+------------------+----------------------------------------------------------------------------
1 | データベース | vacuumを実行することで不要な領域を回収してテーブルの肥大化を防ぎます。
2 | 経費精算 | 交通費や出張旅費の精算は月末までに領収書を添付して申請してください。
3 | ネットワーク | 社内無線LANに接続する際は専用の証明書を端末にインストールしてください。
4 | コンテナ・Docker | 開発用のデータベース環境はDockerコンテナを使ってローカルで起動できます。
5 | セキュリティ規定 | 業務用アカウントのパスワードは12文字以上で設定し使い回しを避けてください。
(5 rows)
vector_db=# SELECT q_text FROM query_target;
q_text
--------------------------------------------------------------
PostgreSQLのインデックスを使ってベクトル検索を高速化する方法
(1 row)
(SELECT q_vec FROM query_target) を条件に使うことで、このクエリ文のベクトルを使った検索ができます。
検証
1. ベクトルデータのサイズとページ配置
まず、入れた384次元のベクトルと日本語の文章がPostgresの中で何バイトくらい使っているのか見てみます。
vector_db=# SELECT
vector_dims(embedding) AS dims,
pg_column_size(embedding) AS vector_bytes,
pg_column_size(items.*) AS total_row_bytes
FROM items LIMIT 1;
dims | vector_bytes | total_row_bytes
------+--------------+-----------------
384 | 1544 | 1696
(1 row)
vector型は1次元あたり4バイト(32-bit float)なので、4 Byte × 384次元 + 8 Byte(ヘッダ) = 1544 Bytesになっています。category や sentence の日本語テキストを合わせるとさらに増え、この例だと1696 Byteです。
続いて、各行がどのページに入っているかを ctid(ページ番号, ページ内の行番号)で見てみます。
vector_db=# SELECT id, ctid, pg_column_size(items.*) AS row_bytes
FROM items WHERE id <= 8 ORDER BY id;
id | ctid | row_bytes
----+-------+-----------
1 | (0,1) | 1696
2 | (0,2) | 1688
3 | (0,3) | 1700
4 | (0,4) | 1700
5 | (1,1) | 1708
6 | (1,2) | 1704
7 | (1,3) | 1700
8 | (1,4) | 1700
(8 rows)
Postgresの1ページはデフォルトで8KB(8,192 Bytes)なので、1行約1,700 Bytesだと1ページに4行((0,1)〜(0,4))入ったところで次のページ (1,1) に移っているのが分かります。
今回は3,000件入れたので、テーブル全体では 3,000 ÷ 4 = 750ページ(6,000 kB)になります。
2. インデックスなし(Seq Scan)と IVFFlat / HNSW の比較
前回の記事のおまけで気になっていた部分の検証です。
3,000件(750ページ)のデータに対して、インデックスなし(Seq Scan)、IVFFlat、HNSW でそれぞれ上位5件を検索し、EXPLAIN (ANALYZE, BUFFERS) で実行時間と読み込んだページ数、検索結果の精度を見てみます。
インデックスなし(Seq Scan)
まずはインデックスを貼らずに検索してみます。
vector_db=# SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | category | sentence
------+--------------+------------------------------------------------------------------------------------------------------
141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
vector_db=# EXPLAIN (ANALYZE, BUFFERS)
SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
Limit (cost=838.34..838.35 rows=5 width=188) (actual time=2.227..2.231 rows=5.00 loops=1)
Buffers: shared hit=751
InitPlan 1
-> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.003..0.005 rows=1.00 loops=1)
Buffers: shared hit=1
-> Sort (cost=837.33..844.83 rows=3000 width=188) (actual time=2.225..2.226 rows=5.00 loops=1)
Sort Key: ((items.embedding <=> (InitPlan 1).col1))
Sort Method: top-N heapsort Memory: 27kB
Buffers: shared hit=751
-> Seq Scan on items (cost=0.00..787.50 rows=3000 width=188) (actual time=0.023..1.910 rows=3000.00 loops=1)
Buffers: shared hit=751
Planning Time: 0.057 ms
Execution Time: 2.273 ms
(13 rows)
Seq Scanなので、items テーブルの750ページとquery_targetの1ページを合わせた751ページ(Buffers: shared hit=751)を読み込んで、3,000件すべてと距離を計算しています。実行時間は2.273 msでした。
検索クエリ(PostgreSQLのインデックスを使ってベクトル検索を高速化する方法)に対して、データベースカテゴリの「PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。」など似た文5件(ID: 141, 1341, 1741, 2541, 2941)が上位5件として返ってきており、これが全件計算したときの正解の5件になります。
IVFFlat インデックス
次に、前回と同じようにIVFFlatインデックスを lists = 100(100個のグループに分割)で作成して検索してみます。
検索時にいくつのグループを調べるかを指定する ivfflat.probesを1と5に変えて実行してみました。
vector_db=# CREATE INDEX items_ivfflat_idx ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
CREATE INDEX
vector_db=# SET ivfflat.probes = 1;
SET
vector_db=# SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | category | sentence
------+--------------+------------------------------------------------------------------------------------------------------
141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
vector_db=# EXPLAIN (ANALYZE, BUFFERS)
SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=17.74..25.56 rows=5 width=188) (actual time=0.036..0.041 rows=5.00 loops=1)
Buffers: shared hit=32
InitPlan 1
-> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.003..0.003 rows=1.00 loops=1)
Buffers: shared hit=1
-> Index Scan using items_ivfflat_idx on items (cost=16.73..4710.00 rows=3000 width=188) (actual time=0.035..0.040 rows=5.00 loops=1)
Order By: (embedding <=> (InitPlan 1).col1)
Index Searches: 1
Buffers: shared hit=32
Planning:
Buffers: shared hit=1
Planning Time: 0.032 ms
Execution Time: 0.051 ms
(13 rows)
probes = 1のときは、100個に分けたグループのうち一番近い1グループだけを見に行くので、読み込んだバッファ数が751 → 32に激減し、実行時間も2.273 ms → 0.051 msと40倍速くなりました。
今回はAIにサンプル文をまとめて生成してもらったせいか似た文章が多くて偏りがあり、たまたま上位5件とも同じ一番近いグループに入っていたため、probes = 1でも5件すべて正解と一致していました。データにばらつきがあってグループの境界付近に正解が散らばっている場合は、probes = 1だと別グループの正解を取りこぼすことがあります。
続いてivfflat.probes = 5に増やしてみます。
vector_db=# SET ivfflat.probes = 5;
SET
vector_db=# SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | category | sentence
------+--------------+------------------------------------------------------------------------------------------------------
141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
vector_db=# EXPLAIN (ANALYZE, BUFFERS)
SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=84.64..92.35 rows=5 width=188) (actual time=0.093..0.097 rows=5.00 loops=1)
Buffers: shared hit=78
InitPlan 1
-> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.003..0.003 rows=1.00 loops=1)
Buffers: shared hit=1
-> Index Scan using items_ivfflat_idx on items (cost=83.62..4710.00 rows=3000 width=188) (actual time=0.092..0.096 rows=5.00 loops=1)
Order By: (embedding <=> (InitPlan 1).col1)
Index Searches: 1
Buffers: shared hit=78
Planning:
Buffers: shared hit=1
Planning Time: 0.032 ms
Execution Time: 0.106 ms
(13 rows)
probes = 5にすると近い5グループを見に行くようになり、読み込むページ数は32 → 78に増えますが、それでも実行時間は0.106 msと、Seq Scan(2.273 ms・751ページ)の20倍以上速くなっています。
なお、IVFFlatのグループ分けはインデックス作成時に乱数で決める部分があるようで、同じデータでもインデックスを作り直すと読み込むページ数などの結果が一致しない場合があります。私も2回目に動かしたときはshared hit=61になりました。後述するHNSWも同様のようです。
簡単に補足です。
近似最近傍探索(ANN)というのは、距離の計算式自体を大雑把に近似しているわけではなく、調べる対象の範囲(グループやグラフの探索範囲)を絞ることで読み込むページ数と計算回数を減らす仕組みです。そのため、探索範囲に入ったデータについてはコサイン距離の数値自体は厳密計算とまったく同じになり、近いグループの中に上位データが収まっていれば順位も数値も変わらない、ということみたいです。これで前回の疑問になっていた部分は検証できたかと思います。
HNSW インデックス
続いて、一度IVFFlatインデックスを消してから、HNSWインデックスを作成して試してみます。
vector_db=# DROP INDEX items_ivfflat_idx;
DROP INDEX
vector_db=# CREATE INDEX items_hnsw_idx ON items USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);
CREATE INDEX
vector_db=# SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | category | sentence
------+--------------+------------------------------------------------------------------------------------------------------
141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
vector_db=# EXPLAIN (ANALYZE, BUFFERS)
SELECT id, category, sentence FROM items
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=470.69..480.01 rows=5 width=188) (actual time=0.208..0.212 rows=5.00 loops=1)
Buffers: shared hit=436
InitPlan 1
-> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.007..0.007 rows=1.00 loops=1)
Buffers: shared hit=1
-> Index Scan using items_hnsw_idx on items (cost=469.68..6064.00 rows=3000 width=188) (actual time=0.207..0.210 rows=5.00 loops=1)
Order By: (embedding <=> (InitPlan 1).col1)
Index Searches: 1
Buffers: shared hit=436
Planning:
Buffers: shared hit=1
Planning Time: 0.069 ms
Execution Time: 0.229 ms
(13 rows)
HNSWは5件とも正解と一致し、実行時間は0.229 msでした。
比較のためにIVFFlatももう一度作って、テーブルと各インデックスのサイズも見比べてみます。
vector_db=# CREATE INDEX items_ivfflat_idx ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
CREATE INDEX
vector_db=# SELECT relname, pg_size_pretty(pg_relation_size(oid)) AS size
FROM pg_class
WHERE relname IN ('items', 'items_ivfflat_idx', 'items_hnsw_idx');
relname | size
-------------------+---------
items | 6000 kB
items_hnsw_idx | 6008 kB
items_ivfflat_idx | 5264 kB
(3 rows)
ここまでの実行時間・バッファ読込数・精度・サイズをまとめると以下のようになりました。
| 検索方法 | 実行時間 | 読込ページ数 (shared hit) | 上位5件の一致数 | インデックスサイズ |
| :--- | ---: | ---: | :---: | ---: |
| インデックスなし (Seq Scan) | 2.273 ms | 751 | 5 / 5(基準) | - |
| IVFFlat (probes = 1) | 0.051 ms | 32 | 5 / 5 | 5264 kB |
| IVFFlat (probes = 5) | 0.106 ms | 78 | 5 / 5 | 5264 kB |
| HNSW(デフォルト) | 0.229 ms | 436 | 5 / 5 | 6008 kB |
IVFFlatは探索するグループ数を絞れるのでバッファ読込数も実行時間もかなり小さく抑えられますが、あらかじめデータが入っている状態で作成しないとグループ分けがうまくいかないという注意点があります。一方、HNSWはデータ追加時にもグラフを繋いでくれてデフォルト設定のまま高い精度が出るので扱いやすいかなと思います。その分、グラフのリンク情報を持つのでインデックスサイズはテーブル本体と同じくらいの大きさ(6008 kB)になっています。
3. 距離計算演算子の比較
前回はコサイン距離(<=>)だけを使いましたが、pgvectorでは全部で6種類の距離計算演算子が用意されています。
| 演算子 | 距離の種類 | 対応する型 | 備考 |
| :---: | :--- | :--- | :--- |
| <=> | コサイン距離(Cosine) | vector, halfvec, sparsevec | ベクトルの向きの違い(0〜2) |
| <-> | L2距離 | vector, halfvec, sparsevec | 2点間の直線距離 |
| <#> | 負の内積(Inner Product) | vector, halfvec, sparsevec | 内積にマイナスを掛けた値 |
| <+> | L1距離 | vector, halfvec, sparsevec | 各次元の差の絶対値の合計 |
| <~> | ハミング距離(Hamming) | bit | 異なるビットの個数 |
| <%> | ジャッカード距離(Jaccard) | bit | 集合の重なり具合(0〜1) |
文章のベクトル検索(RAGなど)では、文章の長さや単語の出現回数によってベクトルの大きさ(長さ)が変わっても、ベクトルの向き(意味の方向)がどれくらい近いかを測れるコサイン距離を使うのが一般的です。
なお、Postgresのインデックススキャンは ORDER BY 演算子 ASCで使う仕組みになっているため、内積も似ているほど値が小さくなるように符号を反転させた負の内積(<#>)になっているようです。
ここではvector型で使える4つの演算子(<=>, <->, <#>, <+>)について、以下の2点に着目して比べてみます。
- 各演算子の実行時間(psqlの \timing で計測)
- コサイン距離で出てきた上位5件と比べて、他の演算子だとどの文章が近いと判定されるか(検索クエリ「PostgreSQLのインデックスを使ってベクトル検索を高速化する方法」に対する近さ)
純粋な距離計算の時間を比べるため、いったんインデックスを削除し、計測をオンにして4つの演算子を順番に実行してみます。
vector_db=# DROP INDEX items_ivfflat_idx, items_hnsw_idx;
DROP INDEX
vector_db=# \timing
Timing is on.
vector_db=# SELECT id, round((embedding <=> (SELECT q_vec FROM query_target))::numeric, 6) AS cosine_dist, sentence
FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | cosine_dist | sentence
------+-------------+------------------------------------------------------------------------------------------------------
141 | 0.086783 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | 0.087194 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | 0.091633 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | 0.097568 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | 0.098207 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
Time: 3.897 ms
vector_db=# SELECT id, round((embedding <-> (SELECT q_vec FROM query_target))::numeric, 6) AS l2_dist, sentence
FROM items ORDER BY embedding <-> (SELECT q_vec FROM query_target) LIMIT 5;
id | l2_dist | sentence
------+----------+------------------------------------------------------------------------------------------------------
141 | 0.416612 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | 0.417598 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | 0.428096 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | 0.441743 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | 0.443185 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
Time: 2.706 ms
vector_db=# SELECT id, round((embedding <#> (SELECT q_vec FROM query_target))::numeric, 6) AS neg_ip, sentence
FROM items ORDER BY embedding <#> (SELECT q_vec FROM query_target) LIMIT 5;
id | neg_ip | sentence
------+-----------+------------------------------------------------------------------------------------------------------
141 | -0.913217 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | -0.912806 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | -0.908367 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | -0.902432 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | -0.901793 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
Time: 2.695 ms
vector_db=# SELECT id, round((embedding <+> (SELECT q_vec FROM query_target))::numeric, 6) AS l1_dist, sentence
FROM items ORDER BY embedding <+> (SELECT q_vec FROM query_target) LIMIT 5;
id | l1_dist | sentence
------+----------+------------------------------------------------------------------------------------------------
141 | 6.382686 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | 6.445336 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | 6.559072 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | 6.849228 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
541 | 6.869993 | 社内ルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
Time: 3.595 ms
4つの演算子の実行時間と、上位5件の結果をまとめると以下の通りです。
| 演算子 | 実行時間 | 上位5件のID | コサイン距離との比較 |
| :---: | ---: | :--- | :--- |
| <=>(コサイン距離) | 3.897 ms | 141, 1341, 1741, 2541, 2941 | 基準(クエリ文に意味が一番近い上位5件) |
| <->(L2距離) | 2.706 ms | 141, 1341, 1741, 2541, 2941 | 上位5件・順位ともコサイン距離と完全に一致 |
| <#>(負の内積) | 2.695 ms | 141, 1341, 1741, 2541, 2941 | 実行時間が最速で、上位5件・順位ともコサイン距離と完全に一致 |
| <+>(L1距離) | 3.595 ms | 141, 1341, 1741, 2941, 541 | 1〜3位は同じだが、4位と5位が入れ替わる |
※文章の比較は一般的にコサイン距離で実施することが多いため、コサイン距離を基準にしています
実行時間で見ると、各次元の掛け算と足し算だけで済む負の内積が2.695 msで一番速く、ベクトルの長さで割る計算が入るコサイン距離が3.897 msと一番時間がかかっています。
また、検索結果の順位を見ると、コサイン距離、L2距離、負の内積の3つが1位から5位までまったく同じ結果になりました。
4. 量子化(halfvec / bit)でどのくらいサイズが下がるか
先ほどHNSWインデックスがテーブル本体と同じくらいのサイズになっていましたが、データ量が増えてきたときにメモリやディスクを節約する機能として、halfvec(16-bit浮動小数点)と binary_quantizeが使えます。
文章検索で一般的なコサイン距離をベースに、元のvector(384)からhalfvec(384)・bit(384)にしたときに、サイズ・実行時間・検索結果がどう変わるかを比べてみました(※ bit型は0と1のビット列でコサイン距離が使えないため、bitのみハミング距離 <~> を使います)。
vector_db=# ALTER TABLE items
ADD COLUMN embedding_half halfvec(384),
ADD COLUMN embedding_bit bit(384);
ALTER TABLE
vector_db=# UPDATE items
SET embedding_half = embedding::halfvec(384),
embedding_bit = binary_quantize(embedding)::bit(384);
UPDATE 3000
vector_db=# ANALYZE items;
ANALYZE
vector_db=# CREATE INDEX items_hnsw_vec_idx ON items USING hnsw (embedding vector_cosine_ops);
CREATE INDEX
vector_db=# CREATE INDEX items_hnsw_half_idx ON items USING hnsw (embedding_half halfvec_cosine_ops);
CREATE INDEX
vector_db=# CREATE INDEX items_hnsw_bit_idx ON items USING hnsw (embedding_bit bit_hamming_ops);
CREATE INDEX
まず、1カラムあたりのバイト数と、HNSWインデックスのサイズを見てみます。
vector_db=# SELECT
pg_column_size(embedding) AS vec_bytes,
pg_column_size(embedding_half) AS half_bytes,
pg_column_size(embedding_bit) AS bit_bytes
FROM items LIMIT 1;
vec_bytes | half_bytes | bit_bytes
-----------+------------+-----------
1540 | 776 | 53
(1 row)
vector_db=# SELECT relname, pg_size_pretty(pg_relation_size(oid)) AS index_size
FROM pg_class
WHERE relname IN ('items_hnsw_vec_idx', 'items_hnsw_half_idx', 'items_hnsw_bit_idx');
relname | index_size
---------------------+------------
items_hnsw_vec_idx | 6008 kB
items_hnsw_half_idx | 3440 kB
items_hnsw_bit_idx | 1032 kB
(3 rows)
そして、実行時間を計測しながらそれぞれのインデックスを使って上位5件を検索してみます。
vector_db=# SELECT id, round((embedding <=> (SELECT q_vec FROM query_target))::numeric, 6) AS cosine_dist, sentence
FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | cosine_dist | sentence
------+-------------+------------------------------------------------------------------------------------------------------
141 | 0.086783 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | 0.087194 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | 0.091633 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | 0.097568 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | 0.098207 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
Time: 0.774 ms
vector_db=# SELECT id, round((embedding_half <=> (SELECT q_vec::halfvec(384) FROM query_target))::numeric, 6) AS cosine_dist, sentence
FROM items ORDER BY embedding_half <=> (SELECT q_vec::halfvec(384) FROM query_target) LIMIT 5;
id | cosine_dist | sentence
------+-------------+------------------------------------------------------------------------------------------------------
141 | 0.086797 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | 0.087198 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1741 | 0.091638 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2541 | 0.097574 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2941 | 0.098213 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
Time: 1.045 ms
vector_db=# SELECT id, (embedding_bit <~> (SELECT binary_quantize(q_vec)::bit(384) FROM query_target)) AS hamming_dist, sentence
FROM items ORDER BY embedding_bit <~> (SELECT binary_quantize(q_vec)::bit(384) FROM query_target) LIMIT 5;
id | hamming_dist | sentence
------+--------------+------------------------------------------------------------------------------------------
1741 | 27 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
2141 | 27 | 日常業務において、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
141 | 27 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
1341 | 27 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
541 | 28 | 社内ルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。
(5 rows)
Time: 0.611 ms
結果をまとめると以下のようになりました。
| データ型(演算子) | 1カラムのサイズ | HNSWインデックスサイズ | 実行時間 | vector(コサイン距離)との結果比較 |
| :--- | ---: | ---: | ---: | :--- |
| vector (<=>) | 1540 Bytes | 6008 kB | 0.774 ms | 基準(上位5件:141, 1341, 1741, 2541, 2941) |
| halfvec (<=>) | 776 Bytes | 3440 kB | 1.045 ms | 上位5件・順位とも完全に一致(距離の小数第5位以下のみ微差) |
| bit (<~>) | 53 Bytes | 1032 kB | 0.611 ms | 似た文章が上位に入るが、同率(27)が並び順位が入れ替わる |
halfvecにすると、カラムサイズもHNSWインデックスのサイズも約半分(6008 kB → 3440 kB)になり、コサイン距離の値も小数第5位以下がほんの少し変わるだけで、検索結果の上位5件は元のvectorとまったく同じでした。実行時間だけ見るとvector(0.774 ms)よりhalfvec(1.045 ms)の方が少し大きくなっていますが、3,000件くらいだとどちらも1ms前後で終わってしまうので、クエリ内の型キャストや実行タイミングの誤差かなと思います(もっと件数大きくしてやり直したいですが大変なので省略)。精度をほぼ落とさずにメモリ・ディスク使用量を半分近く減らせるので、普段使いならhalfvecはかなり良さそうです。
一方、bit型はサイズが53 Bytes(インデックスも約1/6の1032 kB)、実行時間も0.611 msまで下がり、意味が近い「PostgreSQLでインデックスを作成すると〜」の文章群をちゃんと拾えていますが、1次元を正か負かの1ビットに丸めて整数のハミング距離で比較するため、上位4件がすべて距離27で同率になり細かな順位は入れ替わっていました。
5. WHERE句で絞り込んだときの結果0件問題と Iterative Index Scans
最後に、Iterative Index Scans(反復インデックススキャン)を試してみます。
ベクトル検索をするときに WHERE category = 'セキュリティ規定' のようにカテゴリで絞り込みたいケースはよくあると思いますが、HNSWインデックスを使って絞り込み検索をすると、結果が0件になってしまうことがあります。この挙動は hnsw.iterative_scan の設定で切り替えることができます。デフォルトは offです。
今回は全体の5%(3,000件中150件)が該当するcategory = 'セキュリティ規定'という条件で、hnsw.ef_search = 20にして上位5件を検索してみます。
まず hnsw.iterative_scan = off に設定した場合です。
vector_db=# \timing off
Timing is off.
vector_db=# SET hnsw.ef_search = 20;
SET
vector_db=# SET hnsw.iterative_scan = off;
SET
vector_db=# SELECT id, category, sentence FROM items
WHERE category = 'セキュリティ規定'
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | category | sentence
----+----------+----------
(0 rows)
vector_db=# EXPLAIN (ANALYZE, BUFFERS)
SELECT id, category, sentence FROM items
WHERE category = 'セキュリティ規定'
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=289.93..526.84 rows=5 width=188) (actual time=0.277..0.278 rows=0.00 loops=1)
Buffers: shared hit=290
InitPlan 1
-> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.006..0.007 rows=1.00 loops=1)
Buffers: shared hit=1
-> Index Scan using items_hnsw_vec_idx on items (cost=288.92..7396.38 rows=150 width=188) (actual time=0.276..0.277 rows=0.00 loops=1)
Order By: (embedding <=> (InitPlan 1).col1)
Filter: (category = 'セキュリティ規定'::text)
Rows Removed by Filter: 20
Index Searches: 1
Buffers: shared hit=290
Planning:
Buffers: shared hit=1
Planning Time: 0.077 ms
Execution Time: 0.295 ms
(15 rows)
iterative_scan = offのときは、まずHNSWインデックスでベクトルが近い上位20件(ef_search = 20)だけを取ってきて、その20件に対して Filter: (category = 'セキュリティ規定') をかけています。上位20件がすべてデータベースカテゴリの文などで埋まっており、セキュリティ規定が1件も含まれていなかったため(Rows Removed by Filter: 20)、テーブル全体には150件あるのに (0 rows) になってしまいました。
次に hnsw.iterative_scan = relaxed_order に切り替えて同じSQLを実行してみます。
vector_db=# SET hnsw.iterative_scan = relaxed_order;
SET
vector_db=# SELECT id, category, sentence FROM items
WHERE category = 'セキュリティ規定'
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
id | category | sentence
------+------------------+--------------------------------------------------------------------------------------------------------------------------------------
345 | セキュリティ規定 | Webアプリケーションを公開する前には脆弱性診断を実施しSQLインジェクションやXSS対策を確認します。
365 | セキュリティ規定 | パスワードマネージャーを利用してサービスごとに異なるランダムな高強度パスワードを生成・管理します。
1945 | セキュリティ規定 | 基本方針として、Webアプリケーションを公開する前には脆弱性診断を実施しSQLインジェクションやXSS対策を確認します。
1545 | セキュリティ規定 | 原則として、Webアプリケーションを公開する前には脆弱性診断を実施しSQLインジェクションやXSS対策を確認します。
2585 | セキュリティ規定 | セキュリティと品質維持のため、ソースコードや設定ファイルを個人のGitHubアカウントや外部のパブリックリポジトリへ公開してはいけません。
(5 rows)
vector_db=# EXPLAIN (ANALYZE, BUFFERS)
SELECT id, category, sentence FROM items
WHERE category = 'セキュリティ規定'
ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=289.93..526.84 rows=5 width=188) (actual time=1.501..2.168 rows=5.00 loops=1)
Buffers: shared hit=3237
InitPlan 1
-> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.007..0.008 rows=1.00 loops=1)
Buffers: shared hit=1
-> Index Scan using items_hnsw_vec_idx on items (cost=288.92..7396.38 rows=150 width=188) (actual time=1.500..2.165 rows=5.00 loops=1)
Order By: (embedding <=> (InitPlan 1).col1)
Filter: (category = 'セキュリティ規定'::text)
Rows Removed by Filter: 528
Index Searches: 1
Buffers: shared hit=3237
Planning:
Buffers: shared hit=1
Planning Time: 0.113 ms
Execution Time: 2.192 ms
(15 rows)
iterative_scan = relaxed_orderに設定すると、ちゃんとセキュリティ規定の中からSQLインジェクション対策などデータベースに近い文章が5件返ってきました。
EXPLAINの結果を見比べると、裏側で何が起きたかがわかります。offのときはRows Removed by Filter: 20(最初の20件を調べて全部弾かれた時点で終了)だったのに対し、relaxed_orderではRows Removed by Filter: 528、rows=5.00となっており、さらに読み込んだページ数もshared hit=290 → 3237に増えています。つまり、最初の20件で見つからなくても探索を打ち切らず、条件に合うデータが LIMIT 5 件集まるまで(合計533件分)インデックスを自動で掘り進めてくれたことが確認できました。
後片付け
一通り検証が終わったら、作成したテーブルを削除してpsqlから抜けます(テーブルに紐づくインデックスも一緒に削除されます)。
vector_db=# DROP TABLE items, query_target;
DROP TABLE
vector_db=# \q
補足
用語まとめ
最後に、今回の検証やVector Database周りでよく出てくる用語を日本語と英語でまとめておきます。
| 日本語 | 英語 | 説明 |
| :--- | :--- | :--- |
| 埋め込み / ベクトル化 | Embedding | テキストや画像などの意味を、数百〜数千個の数値の配列(ベクトル)に変換すること。 |
| 次元数 | Dimensions | 1つのベクトルに含まれる数値の個数。今回使ったデータは384次元。 |
| 正規化 | Normalization | ベクトルの長さを 1 に揃えること。正規化しておくと内積とコサイン距離の順位が同じになる。 |
| 最近傍探索(厳密検索) | Exact Nearest Neighbor (ENN) / k-NN | 全データと距離を計算して正確な上位K件を探す方法。インデックスなしの Seq Scan がこれにあたる。 |
| 近似最近傍探索 | Approximate Nearest Neighbor (ANN) | 探索する範囲を絞ることで、多少の取りこぼしを許容する代わりに高速に検索する手法。IVFFlat や HNSW が該当する。 |
| 再現率 | Recall | 厳密検索での正解上位K件のうち、近似検索で何割を拾えたかを表す指標。 |
| 転置ファイルインデックス | IVFFlat (Inverted File Flat) | データをあらかじめ複数のグループ(lists)に分けておき、検索時は近いグループ(probes 個)だけを調べるインデックス。 |
| 階層的ナビゲーション可能スモールワールド | HNSW (Hierarchical Navigable Small World) | データを多層のグラフ構造で繋いで探索するインデックス。事前学習なしで高い精度が出やすい。 |
| 量子化 | Quantization | 32-bit浮動小数点(vector)をより少ないビット数で表現して、メモリやディスク使用量を減らす手法。 |
| 半精度浮動小数点(スカラー量子化) | Half-Precision Float (halfvec) | 1次元を32-bitから16-bit(2バイト)に減らすデータ型。精度をあまり落とさずにサイズを約半分にできる。 |
| バイナリ量子化 | Binary Quantization (binary_quantize) | 1次元を正負の 0 か 1(1ビット)に圧縮する手法。データサイズは約1/32になる。 |
| 疎ベクトル / 密ベクトル | Sparse Vector (sparsevec) / Dense Vector | ほとんどの要素に値が入っている通常のベクトルが Dense Vector、単語の出現頻度のように大半の要素が 0 のベクトルが Sparse Vector。 |
| 再ランキング | Re-ranking | 軽いインデックス(bit など)で多めに候補を取ってきたあと、元の vector などで距離を計算し直して上位K件に並べ替える手法。 |
| 反復インデックススキャン | Iterative Index Scans | WHERE 句で絞り込みをしたときに、LIMIT の件数に達するまでインデックス探索を自動で繰り返す機能。 |
| ページ(ブロック) | Page / Block | Postgresがディスクやメモリ(shared_buffers)を読み書きする基本単位(デフォルトは8KB)。 |
おわりに
前回の記事で疑問に残っていた「なぜ近似検索なのに結果や距離の数値が変わらなかったのか」というところから、pgvectorの各機能まで一通り実機で動かして確認できました。
実際に日本語の文章データを入れてpsqlでEXPLAIN (ANALYZE, BUFFERS)やインデックスのサイズを見ながら動かすと、裏側で何をやっているのかイメージしやすかったです。特にドキュメントを読んだだけではIterative Index Scansの何がIterative(反復)なのか理解できなかったのですが、実際の動きを見たらわかりやすかったです。
なお、今回の検証で試した機能や設定については基本的にすべてpgvector公式GitHubのREADMEに載っているので、細かいパラメータや仕様が気になった方はそちらもあわせて参照してみてください。
pgvectorはもうすぐ 0.9.0が公開されそうです。楽しみですね!
以上です。最後まで読んでいただきありがとうございます!
参考
- pgvector (GitHub)
- pgvector/pgvector
- 前回の記事:pgvectorで学ぶVector Database(RAGの基礎)
- qiita.com
1 like
@kartikktwt Benchmark pgvector with the filters your app will use. Its approximate indexes apply filtering after the scan, so selective filters can return fewer rows than LIMIT; iterative scans can help.
pgvector/pgvector
2 views
The Ultimate Developer Stack: 23 Trending GitHub Repos | 28-10-2026 | Dev Repos Daily
cutt.ly
🔥 Nobody Told You About This New AI Repo (Summer2027-Internships)
Stay on top of the open source ecosystem with this handpicked selection of trending GitHub repositories. From innovative developer tools to groundbreaking frameworks, these are the projects making waves in the software community right now.
October 28, 2026
What is inside this video:
- Top 23 trending GitHub repositories ranked by stars gained today
- Developer insights and project overviews for every featured repo
- AI-narrated walkthrough of each open source project
- Direct links to all repositories below for easy access
⏱️ TIMESTAMPS (YouTube Chapters):
00:00 - Intro: Today's High-Impact Tools
00:09 - Trending Leaderboard Overview
00:25 - #1 Summer2027-Internships
00:54 - #2 n8n
01:24 - #3 datahub
01:45 - #4 upscayl
02:08 - #5 free-for-dev
02:33 - #6 awesome-remote-job
02:59 - #7 Data-Science-For-Beginners
03:27 - #8 PowerToys
03:50 - #9 neovim
04:10 - #10 jellyfin
04:33 - #11 llama_index
04:56 - #12 syft
05:18 - #13 playwright
05:46 - #14 plane
06:09 - #15 pgvector
06:28 - #16 awesome
06:59 - #17 runner-images
07:19 - #18 rustdesk
07:43 - #19 lazygit
08:05 - #20 transformers
08:31 - #21 directus
09:02 - #22 gitleaks
09:22 - #23 OpenCore-Legacy-Patcher
09:45 - Outro & Key Takeaways
━━━━━━━━━━━━━━━━━━━━━━━
TODAY'S TOP 23 TRENDING REPOSITORIES:
━━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Summer2027-Internships (⭐ 48.2k • +21 today • Python)
Summer 2027 software engineering, data science, AI, quant, product management, and hardware internship postings. Updated daily by Simplify and Pitt CSC.
🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208.9k • +161 today • TypeScript)
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12.9k • +10 today • Python)
The Context Platform for your Data and AI Stack
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51.2k • +76 today • TypeScript)
🆙 Upscayl - #1 Free and Open Source AI Image Upscaler for Linux, MacOS and Windows.
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2k • +55 today • HTML)
A list of SaaS, PaaS and IaaS offerings that have free tiers of interest to devops and infradev
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 today • Unknown)
A curated list of awesome remote jobs and resources. Inspired by vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 today • Jupyter Notebook)
10 Weeks, 20 Lessons, Data Science for All!
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140.1k • +84 today • C)
Microsoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103.2k • +41 today • Vim Script)
Vim-fork focused on extensibility and usability
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58.7k • +74 today • C#)
The Free Software Media System - Server Backend & API
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52.7k • +23 today • Python)
LlamaIndex is the document processing platform for AI
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9.8k • +14 today • Go)
CLI tool and library for generating a Software Bill of Materials from container images and filesystems
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98.7k • +90 today • TypeScript)
Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61.6k • +64 today • TypeScript)
🔥🔥🔥 Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage.
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23.5k • +17 today • C)
Open-source vector similarity search for Postgres
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━━
Subscribe to @devrepos for daily GitHub trending repositories, open source roundups, and developer news.
New videos every day covering the best open source software and trending projects on GitHub.
[ar] أفضل حزمة أدوات للمطورين: 23 مستودعاً رائجاً على GitHub | 28-10-2026 | مستودعات المطورين اليومية
cutt.ly
🔥 لم يخبرك أحد عن هذا المستودع الجديد للذكاء الاصطناعي (تدريب صيفي 2027)
ابقَ على اطلاع دائم بأحدث التطورات في عالم البرمجيات مفتوحة المصدر مع هذه المجموعة المختارة بعناية من مستودعات GitHub الرائجة. من أدوات تطوير مبتكرة إلى أطر عمل رائدة، هذه هي المشاريع التي تُحدث ضجة في مجتمع البرمجيات حاليًا.
... ٢٨ أكتوبر ٢٠٢٦
محتوى هذا الفيديو:
- أفضل ٢٣ مستودعًا رائجًا على GitHub، مُرتبة حسب عدد النجوم المكتسبة اليوم
- رؤى المطورين ونظرة عامة على المشاريع لكل مستودع مميز
- شرح صوتي مُعزز بالذكاء الاصطناعي لكل مشروع مفتوح المصدر
- روابط مباشرة لجميع المستودعات أدناه لسهولة الوصول
⏱️ الفواصل الزمنية (فصول يوتيوب):
٠٠:٠٠ - مقدمة: أدوات اليوم الأكثر تأثيرًا
٠٠:٠٩ - نظرة عامة على قائمة المتصدرين الرائجة
٠٠:٢٥ - #١ تدريب صيفي ٢٠٢٧
٠٠:٥٤ - #٢ n8n
٠١:٢٤ - #٣ datahub
٠١:٤٥ - #٤ upscayl
٠٢:٠٨ - #٥ free-for-dev
٠٢:٣٣ - #٦ awesome-remote-job
٠٢:٥٩ - #٧ علوم البيانات للمبتدئين
٠٣:٢٧ - #٨ باور تويز
03:50 - #9 نيوفيم
04:10 - #10 جيلي فين
04:33 - #11 لاما إندكس
04:56 - #12 سيفت
05:18 - #13 بلاي رايت
05:46 - #14 بلين
06:09 - #15 بي جي فيكتور
06:28 - #16 أوسوم
06:59 - #17 رانر إيمجز
07:19 - #18 رست ديسك
07:43 - #19 ليزي جيت
08:05 - #20 ترانسفورمرز
08:31 - #21 دايركت توس
09:02 - #22 جيت ليكس
09:22 - #23 أوبن كور ليجاسي باتشر
09:45 - الخاتمة والمفتاح أهم النقاط
━━━━━━━━━━━━━━━━━━━━━━━━
أفضل 23 موقعًا رائجًا اليوم:
━━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Summer2027-Internships (⭐ 48.2 ألف • +21 اليوم • بايثون)
فرص تدريب صيفية لعام 2027 في هندسة البرمجيات، وعلوم البيانات، والذكاء الاصطناعي، والتحليل الكمي، وإدارة المنتجات، والأجهزة. يتم تحديثها يوميًا بواسطة Simplify و Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208.9 ألف • +161 اليوم • TypeScript) منصة أتمتة سير العمل البرمجية العادلة مع إمكانيات ذكاء اصطناعي مدمجة. اجمع بين البناء المرئي والبرمجة المخصصة، مع إمكانية الاستضافة الذاتية أو السحابية، وأكثر من 400 تكامل.
منصة أتمتة سير العمل البرمجية العادلة مع إمكانيات الذكاء الاصطناعي المدمجة. 🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12.9 ألف • +10 اليوم • بايثون)
منصة السياق لبياناتك وتقنيات الذكاء الاصطناعي
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51.2 ألف • +76 اليوم • تايب سكريبت)
🆙 Upscayl - برنامج مجاني ومفتوح المصدر لتحسين جودة الصور بتقنية الذكاء الاصطناعي، يعمل على أنظمة لينكس وماك أو إس وويندوز.
...
#3 🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2 ألف • +55 اليوم • HTML)
قائمة بعروض SaaS وPaaS وIaaS التي تتضمن مستويات مجانية تهم مطوري DevOps وInfradev
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50 ألف • +99 اليوم • غير معروف)
قائمة منتقاة من أفضل الوظائف والموارد عن بُعد. مستوحى من vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 مايكروسوفت/علوم البيانات للمبتدئين (⭐ 37.8 ألف • +47 اليوم • Jupyter Notebook)
10 أسابيع، 20 درسًا، علوم البيانات للجميع!
#7 🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140.1 ألف • +84 اليوم • C)
مجموعة أدوات Microsoft PowerToys تُعزز الإنتاجية وتُتيح تخصيص نظام Windows.
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103.2 ألف • +41 اليوم • سكربت Vim)
نسخة مُعدّلة من Vim تُركز على قابلية التوسع وسهولة الاستخدام.
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58.7 ألف • +74 اليوم • C#)
نظام الوسائط البرمجية الحرة - خادم خلفي وواجهة برمجة تطبيقات (API)
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ ٥٢٫٧ ألف • +٢٣ اليوم • بايثون)
LlamaIndex هي منصة معالجة المستندات للذكاء الاصطناعي
🔗 run-llama/llama_index
#١٢ anchore/syft (⭐ ٩٫٨ ألف • +١٤ اليوم • جو)
أداة سطر أوامر ومكتبة لإنشاء قائمة مكونات برمجية من صور الحاويات وأنظمة الملفات
🔗 anchore/syft
#١٣ microsoft/playwright (⭐ ٩٨٫٧ ألف • +٩٠ اليوم • تايب سكريبت)
Playwright هو إطار عمل لاختبار وأتمتة الويب. يتيح اختبار Chromium وFirefox وWebKit باستخدام واجهة برمجة تطبيقات واحدة.
#١٣ microsoft/playwright (⭐ ٩٨٫٧ ألف • +٩٠ اليوم • تايب سكريبت)
Playwright هو إطار عمل لاختبار وأتمتة الويب. يتيح اختبار Chromium وFirefox وWebKit باستخدام واجهة برمجة تطبيقات واحدة. 🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61.6 ألف • +64 اليوم • TypeScript)
🔥🔥🔥 بديل مفتوح المصدر لـ Jira وLinear وMonday وClickUp. Plane منصة حديثة لإدارة المشاريع، تُتيح إدارة المهام، والسباقات، والوثائق، وفرز المهام.
Plane 🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23.5 ألف • +17 اليوم • C)
بحث مفتوح المصدر عن تشابه المتجهات لـ Postgres
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━━
اشترك في @devrepos للاطلاع على أحدث مستودعات GitHub الرائجة، وملخصات المشاريع مفتوحة المصدر، وأخبار المطورين.
فيديوهات جديدة يوميًا تغطي أفضل برامج المصادر المفتوحة والمشاريع الرائجة على GitHub.
[bn] ডেভেলপারদের জন্য সেরা কালেকশন: ২৩টি ট্রেন্ডিং গিটহাব রিপোজিটরি | ২৮-১০-২০২৬ | ডেভ রিপোস ডেইলি
cutt.ly
🔥 এই নতুন এআই রিপোটির কথা আপনাকে কেউ বলেনি (সামার ২০২৭-ইন্টার্নশিপ)
ট্রেন্ডিং গিটহাব রিপোজিটরিগুলোর এই বিশেষভাবে নির্বাচিত সংগ্রহের মাধ্যমে ওপেন সোর্স ইকোসিস্টেমের সাথে আপ-টু-ডেট থাকুন। উদ্ভাবনী ডেভেলপার টুলস থেকে শুরু করে যুগান্তকারী ফ্রেমওয়ার্ক পর্যন্ত, এই প্রজেক্টগুলোই এখন সফটওয়্যার কমিউনিটিতে আলোড়ন সৃষ্টি করছে।
২৮শে অক্টোবর, ২০২৬
এই ভিডিওতে যা আছে:
আজ অর্জিত স্টারের ভিত্তিতে র্যাঙ্ক করা শীর্ষ ২৩টি ট্রেন্ডিং গিটহাব রিপোজিটরি
- প্রতিটি ফিচার করা রিপোর জন্য ডেভেলপারদের মতামত এবং প্রজেক্টের সংক্ষিপ্ত বিবরণ
- প্রতিটি ওপেন সোর্স প্রজেক্টের AI-বর্ণিত ওয়াকথ্রু
- সহজে অ্যাক্সেসের জন্য নিচে সমস্ত রিপোজিটরির সরাসরি লিঙ্ক
⏱️ টাইমস্ট্যাম্প (ইউটিউব চ্যাপ্টার):
০০:০০ - ভূমিকা: আজকের হাই-ইমপ্যাক্ট টুলস
০০:০৯ - ট্রেন্ডিং লিডারবোর্ডের সংক্ষিপ্ত বিবরণ
০০:২৫ - #১ Summer2027-Internships
০০:৫৪ - #২ n8n
০১:২৪ - #৩ datahub
০১:৪৫ - #৪ upscayl
০২:০৮ - #৫ free-for-dev
০২:৩৩ - #৬ awesome-remote-job
০২:৫৯ - #৭ Data-Science-For-Beginners
০৩:২৭ - #৮ পাওয়ারটয়েজ
০৩:৫০ - #৯ নিওভিম
০৪:১০ - #১০ জেলিফিন
০৪:৩৩ - #১১ লামা_ইনডেক্স
০৪:৫৬ - #১২ সাইফট
০৫:১৮ - #১৩ প্লেরাইট
০৫:৪৬ - #১৪ প্লেন
০৬:০৯ - #১৫ পিজিভেক্টর
০৬:২৮ - #১৬ অসাম
০৬:৫৯ - #১৭ রানার-ইমেজেস
০৭:১৯ - #১৮ রাস্টডেস্ক
০৭:৪৩ - #১৯ লেজিগিট
০৮:০৫ - #২০ ট্রান্সফর্মার্স
০৮:৩১ - #২১ ডিরেক্টাস
০৯:০২ - #২২ গিটলিকস
০৯:২২ - #২৩ ওপেনকোর-লেগ্যাসি-প্যাচার
০৯:৪৫ - আউটরো ও কী মূল কথা
━━━━━━━━━━━━━━━━━━━━━━━
আজকের শীর্ষ ২৩টি ট্রেন্ডিং রিপোজিটরি:
━━━━━━━━━━━━━━━━━━━━━━
#১ SimplifyJobs/Summer2027-Internships (⭐ ৪৮.২ হাজার • আজ +২১ • পাইথন)
সামার ২০২৭ সফটওয়্যার ইঞ্জিনিয়ারিং, ডেটা সায়েন্স, এআই, কোয়ান্ট, প্রোডাক্ট ম্যানেজমেন্ট, এবং হার্ডওয়্যার ইন্টার্নশিপের পোস্ট। Simplify এবং Pitt CSC দ্বারা প্রতিদিন আপডেট করা হয়।
🔗 SimplifyJobs/Summer2027-Internships
#২ n8n-io/n8n (⭐ ২০৮.৯ হাজার • আজ +১৬১ • টাইপস্ক্রিপ্ট)
নেটিভ এআই সক্ষমতাসহ ফেয়ার-কোড ওয়ার্কফ্লো অটোমেশন প্ল্যাটফর্ম। ভিজ্যুয়াল বিল্ডিংয়ের সাথে কাস্টম কোড, সেলফ-হোস্ট বা ক্লাউড, ৪০০+ ইন্টিগ্রেশন একত্রিত করুন।
🔗 n8n-io/n8n
#৩ datahub-project/datahub (⭐ ১২.৯ হাজার • আজ +১০ • পাইথন)
আপনার ডেটা এবং এআই স্ট্যাকের জন্য কনটেক্সট প্ল্যাটফর্ম।
🔗 datahub-project/datahub
#৪ upscayl/upscayl (⭐ ৫১.২ হাজার • আজ +৭৬ • টাইপস্ক্রিপ্ট)
🆙 Upscayl - লিনাক্স, ম্যাকওএস এবং উইন্ডোজের জন্য #১ ফ্রি এবং ওপেন সোর্স এআই ইমেজ আপস্কেলার।
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2k • আজ +55 • HTML)
SaaS, PaaS এবং IaaS অফারগুলির একটি তালিকা, যেগুলির ফ্রি টিয়ার রয়েছে এবং যা ডেভঅপ্স ও ইনফ্রাডেভের জন্য আকর্ষণীয়।
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50k • আজ +99 • অজানা)
চমৎকার রিমোট চাকরি এবং রিসোর্সের একটি সংকলিত তালিকা। vinta/awesome-python দ্বারা অনুপ্রাণিত
🔗 lukasz-madon/awesome-remote-job
#৭ microsoft/Data-Science-For-Beginners (⭐ ৩৭.৮ হাজার • আজ +৪৭ • জুপিটার নোটবুক)
১০ সপ্তাহ, ২০টি পাঠ, সকলের জন্য ডেটা সায়েন্স!
🔗 microsoft/Data-Science-For-Beginners
#৮ microsoft/PowerToys (⭐ ১৪০.১ হাজার • আজ +৮৪ • C)
মাইক্রোসফট পাওয়ারটয়েজ হলো ইউটিলিটিগুলোর একটি সংগ্রহ যা উইন্ডোজে উৎপাদনশীলতা এবং কাস্টমাইজেশনকে দারুণভাবে বাড়িয়ে তোলে।
🔗 microsoft/PowerToys
#৯ neovim/neovim (⭐ ১০৩.২ হাজার • আজ +৪১ • Vim Script)
এক্সটেনসিবিলিটি এবং ব্যবহারযোগ্যতার উপর দৃষ্টি নিবদ্ধ একটি ভিম-ফর্ক।
🔗 neovim/neovim
#১০ jellyfin/jellyfin (⭐ ৫৮.৭ হাজার • আজ +৭৪ • C#) ফ্রি সফটওয়্যার মিডিয়া সিস্টেম - সার্ভার ব্যাকএন্ড এবং এপিআই।
🔗 jellyfin/jellyfin
#১১ run-llama/llama_index (⭐ ৫২.৭ হাজার • আজ +২৩) • পাইথন)
লামা ইনডেক্স (LlamaIndex) হলো এআই (AI)-এর জন্য ডকুমেন্ট প্রসেসিং প্ল্যাটফর্ম
🔗 run-llama/llama_index
#১২ অ্যাঙ্কোর/সিফট (⭐ ৯.৮ হাজার • আজ +১৪ • গো)
কন্টেইনার ইমেজ এবং ফাইলসিস্টেম থেকে সফটওয়্যার বিল অফ মেটেরিয়ালস (Software Bill of Materials) তৈরি করার জন্য একটি সিএলআই (CLI) টুল এবং লাইব্রেরি
🔗 anchore/syft
#১৩ মাইক্রোসফট/প্লেরাইট (⭐ ৯৮.৭ হাজার • আজ +৯০ • টাইপস্ক্রিপ্ট)
প্লেরাইট (Playwright) হলো ওয়েব টেস্টিং এবং অটোমেশনের জন্য একটি ফ্রেমওয়ার্ক। এটি একটিমাত্র এপিআই (API) দিয়ে ক্রোমিয়াম (Chromium), ফায়ারফক্স (Firefox) এবং ওয়েবকিট (WebKit) পরীক্ষা করার সুযোগ দেয়।
🔗 microsoft/playwright
#১৪ মেকপ্লেন/প্লেন (⭐ ৬১.৬ হাজার • আজ +৬৪ • টাইপস্ক্রিপ্ট)
🔥🔥🔥 ওপেন-সোর্স জিরা (Jira), লিনিয়ার (Linear), মানডে (Monday), এবং ক্লিকআপ (ClickUp)-এর বিকল্প। প্লেন হলো টাস্ক, স্প্রিন্ট, ডক্স এবং ট্রায়েজ পরিচালনার জন্য একটি আধুনিক প্রজেক্ট ম্যানেজমেন্ট প্ল্যাটফর্ম।
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ ২৩.৫ হাজার • আজ +১৭ • C)
পোস্টগ্রেসের জন্য ওপেন-সোর্স ভেক্টর সিমিলারিটি সার্চ
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━
প্রতিদিনের গিটহাব ট্রেন্ডিং রিপোজিটরি, ওপেন সোর্স রাউন্ডআপ এবং ডেভেলপার নিউজের জন্য @devrepos-এ সাবস্ক্রাইব করুন।
প্রতিদিন গিটহাবের সেরা ওপেন সোর্স সফটওয়্যার এবং ট্রেন্ডিং প্রজেক্টগুলো নিয়ে নতুন ভিডিও আসে।
[de-DE] Der ultimative Entwickler-Stack: 23 angesagte GitHub-Repos | 28.10.2026 | Dev Repos Daily
cutt.ly
🔥 Dieses neue KI-Repository ist noch ein Geheimtipp (Sommer 2027 – Praktika)
Bleiben Sie mit dieser handverlesenen Auswahl angesagter GitHub-Repositories immer auf dem Laufenden im Open-Source-Ökosystem. Von innovativen Entwicklertools bis hin zu bahnbrechenden Frameworks – diese Projekte begeistern die Software-Community geradezu.
28. Oktober 2026
Inhalt dieses Videos:
- Die 23 beliebtesten GitHub-Repositories, sortiert nach den heute erhaltenen Sternen
- Entwickler-Einblicke und Projektübersichten zu jedem vorgestellten Repository
- KI-gestützter Rundgang durch jedes Open-Source-Projekt
- Direkte Links zu allen Repositories für einfachen Zugriff
⏱️ ZEITSTEMPEL (YouTube-Kapitel):
00:00 - Intro: Die wichtigsten Tools von heute
00:09 - Übersicht der beliebtesten Repositories
00:25 - #1 Sommer 2027 – Praktika
00:54 - #2 n8n
01:24 - #3 datahub
01:45 - #4 upscayl
02:08 - #5 free-for-dev
02:33 - #6 awesome-remote-job
02:59 - #7 Data-Science-For-Beginners
03:27 - #8 PowerToys
03:50 – #9 neovim
04:10 – #10 jellyfin
04:33 – #11 llama_index
04:56 – #12 syft
05:18 – #13 playwright
05:46 – #14 plane
06:09 – #15 pgvector
06:28 – #16 awesome
06:59 – #17 runner-images
07:19 – #18 rustdesk
07:43 – #19 lazygit
08:05 – #20 transformers
08:31 – #21 directus
09:02 – #22 gitleaks
09:22 – #23 OpenCore-Legacy-Patcher
09:45 – Abspann & Legende Wichtigste Erkenntnisse
━━━━━━━━━━━━━━━━━━━━━━━
Die 23 beliebtesten Jobportale von heute:
━━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Sommer 2027 – Praktika (⭐ 48,2k • +21 heute • Python)
Stellenangebote für Praktika im Bereich Softwareentwicklung, Data Science, KI, Quantitative Methoden, Produktmanagement und Hardware im Sommer 2027. Täglich aktualisiert von Simplify und Pitt CSC.
🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208,9k • +161 heute • TypeScript)
Fair-Code-Workflow-Automatisierungsplattform mit nativen KI-Funktionen. Visuelles Erstellen mit benutzerdefiniertem Code kombinieren, selbst hosten oder in der Cloud, über 400 Integrationen.
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12,9k • +10 heute • Python)
Die Kontextplattform für Ihren Daten- und KI-Stack.
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51,2k • +76 heute • TypeScript)
🆙 Upscayl – Nr. 1 kostenloser Open-Source-KI-Bild-Upscaler für Linux, macOS und Windows.
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.200 • +55 heute • HTML)
Eine Liste von SaaS-, PaaS- und IaaS-Angeboten mit kostenlosen Tarifen, die für DevOps- und Infrastrukturentwickler interessant sind.
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50.000 • +99 heute • Unbekannt)
Eine kuratierte Liste mit tollen Remote-Jobs und Ressourcen. Inspiriert von vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Data-Science-For-Beginners (⭐ 37,8k • +47 heute • Jupyter Notebook)
10 Wochen, 20 Lektionen: Data Science für alle!
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140,1k • +84 heute • C)
Microsoft PowerToys ist eine Sammlung von Hilfsprogrammen, die die Produktivität und Anpassungsmöglichkeiten unter Windows deutlich verbessern.
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103,2k • +41 heute • Vim Script)
Vim-Fork mit Fokus auf Erweiterbarkeit und Benutzerfreundlichkeit.
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58,7k • +74 heute • C#)
Das Free Software Media System – Server-Backend & API
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52,7k • +23 heute • Python)
LlamaIndex ist die Dokumentenverarbeitungsplattform für KI.
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9,8k • +14 heute • Go)
CLI-Tool und Bibliothek zur Generierung einer Software-Stückliste aus Container-Images und Dateisystemen.
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98,7k • +90 heute • TypeScript)
Playwright ist ein Framework für Webtests und -automatisierung. Es ermöglicht das Testen von Chromium, Firefox und WebKit mit einer einzigen API.
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61,6k • +64 heute • TypeScript)
🔥🔥🔥 Plane ist eine Open-Source-Alternative zu Jira, Linear, Monday und ClickUp. Es handelt sich um eine moderne Projektmanagement-Plattform zur Verwaltung von Aufgaben, Sprints, Dokumenten und Priorisierung.
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23,5k • +17 heute • C)
Open-Source-Vektorähnlichkeitssuche für PostgreSQL
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━━━
Abonniere @devrepos für täglich aktuelle GitHub-Repositories, Open-Source-Übersichten und Entwickler-News. Täglich neue Videos zu den besten Open-Source-Softwareprojekten und Trendprojekten auf GitHub.
[es-US] El stack definitivo para desarrolladores: 23 repositorios de GitHub en tendencia | 28/10/2026 | D...
cutt.ly
🔥 Nadie te habló de este nuevo repositorio de IA (Prácticas de verano de 2027)
Mantente al día con el ecosistema de código abierto con esta selección de repositorios de GitHub que marcan tendencia. Desde herramientas innovadoras para desarrolladores hasta frameworks revolucionarios, estos son los proyectos que están causando sensación en la comunidad de software.
28 de octubre de 2026
Contenido de este video:
- Los 23 repositorios de GitHub más populares, clasificados según las estrellas obtenidas hoy.
- Información para desarrolladores y descripciones generales de cada repositorio destacado.
- Tutorial guiado por IA de cada proyecto de código abierto.
- Enlaces directos a todos los repositorios a continuación para un acceso fácil.
⏱️ MARCAS DE TIEMPO (Capítulos de YouTube):
00:00 - Introducción: Herramientas de alto impacto de hoy
00:09 - Resumen de la clasificación de tendencias
00:25 - N.° 1: Prácticas de verano de 2027
00:54 - N.° 2: n8n
01:24 - N.° 3: datahub
01:45 - N.° 4: upscayl
02:08 - N.° 5: free-for-dev
02:33 - N.° 6: awesome-remote-job
02:59 - N.° 7: Ciencia de datos para principiantes
03:27 - N.° 8 PowerToys
03:50 - #9 neovim
04:10 - #10 jellyfin
04:33 - #11 llama_index
04:56 - #12 syft
05:18 - #13 playwright
05:46 - #14 plane
06:09 - #15 pgvector
06:28 - #16 awesome
06:59 - #17 runner-images
07:19 - #18 rustdesk
07:43 - #19 lazygit
08:05 - #20 transformers
08:31 - #21 directus
09:02 - #22 gitleaks
09:22 - #23 OpenCore-Legacy-Patcher
09:45 - Outro y clave Conclusiones
━━━━━━━━━━━━━━━━━━━━━━━
LOS 23 REPOSITORIOS MÁS POPULARES DE HOY:
━━━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Summer2027-Interships (⭐ 48.2k • +21 hoy • Python)
Ofertas de prácticas de verano de 2027 en ingeniería de software, ciencia de datos, IA, análisis cuantitativo, gestión de productos y hardware. Actualizado diariamente por Simplify y Pitt CSC.
🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208.9k • +161 hoy • TypeScript)
Plataforma de automatización de flujos de trabajo con código justo y capacidades de IA nativas. Combina la creación visual con código personalizado, autoalojamiento o en la nube, más de 400 integraciones.
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12.9k • +10 hoy • Python)
La plataforma de contexto para tu pila de datos e IA.
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51.2k • +76 hoy • TypeScript)
🆙 Upscayl: el escalador de imágenes con IA gratuito y de código abierto n.° 1 para Linux, macOS y Windows.
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2k • +55 hoy • HTML)
Una lista de ofertas de SaaS, PaaS e IaaS con planes gratuitos de interés para devops e infradev.
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 hoy • Desconocido)
Una lista seleccionada de excelentes trabajos y recursos remotos. Inspirado en vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Ciencia de Datos para Principiantes (⭐ 37.8k • +47 hoy • Jupyter Notebook)
10 semanas, 20 lecciones: ¡Ciencia de Datos para todos!
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140.1k • +84 hoy • C)
Microsoft PowerToys es una colección de utilidades que potencian la productividad y la personalización en Windows.
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103.2k • +41 hoy • Vim Script)
Bifurcación de Vim centrada en la extensibilidad y la usabilidad.
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58.7k • +74 hoy • C#)
Sistema de medios de software libre: backend y API del servidor.
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52.7k • +23 hoy • Python)
LlamaIndex es la plataforma de procesamiento de documentos para IA.
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9.8k • +14 hoy • Go)
Herramienta y biblioteca de línea de comandos para generar una lista de materiales de software a partir de imágenes de contenedores y sistemas de archivos.
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98.7k • +90 hoy • TypeScript)
Playwright es un framework para pruebas y automatización web. Permite probar Chromium, Firefox y WebKit con una única API.
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61.6k • +64 hoy • TypeScript)
🔥🔥🔥 Alternativa de código abierto a Jira, Linear, Monday y ClickUp. Plane es una plataforma moderna de gestión de proyectos para administrar tareas, sprints, documentación y priorización de tareas.
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23.5k • +17 hoy • C)
Búsqueda de similitud vectorial de código abierto para PostgreSQL
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━━━
Suscríbete a @devrepos para ver diariamente los repositorios más populares de GitHub, resúmenes de código abierto y noticias para desarrolladores.
Nuevos videos cada d...
[fr-FR] Le stack ultime du développeur : 23 dépôts GitHub en vogue | 28/10/2026 | Dev Repos Daily
cutt.ly
🔥 Personne ne vous a parlé de ce nouveau dépôt d'IA (Stages été 2027)
Restez à la pointe de l'écosystème open source grâce à cette sélection exclusive de dépôts GitHub incontournables. Des outils de développement innovants aux frameworks révolutionnaires, découvrez les projets qui font sensation dans la communauté du logiciel en ce moment.
28 octobre 2026
Contenu de cette vidéo :
- Les 23 dépôts GitHub les plus populaires, classés par nombre d'étoiles gagnées aujourd'hui
- Présentations et analyses de chaque dépôt mis en avant
- Visite guidée commentée par une IA de chaque projet open source
- Liens directs vers tous les dépôts ci-dessous pour un accès facile
⏱️ HORODATAGE (Chapitres YouTube) :
00:00 - Introduction : Les outils à fort impact du jour
00:09 - Aperçu du classement des tendances
00:25 - N° 1 Summer2027-Internships
00:54 - N° 2 n8n
01:24 - N° 3 datahub
01:45 - N° 4 upscayl
02:08 - N° 5 free-for-dev
02:33 - N° 6 awesome-remote-job
02:59 - N° 7 Data-Science-For-Beginners
03:27 - N° 8 PowerToys
03:50 - #9 neovim
04:10 - #10 jellyfin
04:33 - #11 llama_index
04:56 - #12 syft
05:18 - #13 playwright
05:46 - #14 plane
06:09 - #15 pgvector
06:28 - #16 awesome
06:59 - #17 runner-images
07:19 - #18 rustdesk
07:43 - #19 lazygit
08:05 - #20 transformers
08:31 - #21 directus
09:02 - #22 gitleaks
09:22 - #23 OpenCore-Legacy-Patcher
09:45 - Conclusion et légende Points clés
━━━━━━━━━━━━━━━━━━━━━━
TOP 23 DES DÉPÔTS LES PLUS CONSULTÉS AUJOURD'HUI :
━━━━━━━━━━━━━━━━━━━━━━━
N° 1 SimplifyJobs/Stages Été 2027 (⭐ 48,2 k • +21 aujourd'hui • Python)
Offres de stage Été 2027 en génie logiciel, science des données, IA, analyse quantitative, gestion de produits et matériel informatique. Mise à jour quotidienne par Simplify et Pitt CSC.
🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208,9 k • +161 aujourd'hui • TypeScript)
Plateforme d'automatisation des flux de travail FairCode avec des fonctionnalités d'IA natives. Combinez la création visuelle avec du code personnalisé, auto-hébergé ou cloud, plus de 400 intégrations.
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12,9 k • +10 aujourd'hui • Python)
La plateforme Context pour votre stack de données et d'IA
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51,2 k • +76 aujourd'hui • TypeScript)
🆙 Upscayl - Upscaler d'images IA gratuit et open source n° 1 pour Linux, macOS et Windows.
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140,2 k • +55 aujourd'hui • HTML)
Liste d'offres SaaS, PaaS et IaaS proposant des versions gratuites intéressantes pour les développeurs DevOps et Infrastructure.
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50 k • +99 aujourd'hui • Inconnu)
Sélection d'offres d'emploi et de ressources intéressantes pour le télétravail. Inspiré par vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Data-Science-For-Beginners (⭐ 37,8 k • +47 aujourd'hui • Jupyter Notebook)
10 semaines, 20 leçons : la science des données pour tous !
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140,1 k • +84 aujourd'hui • C)
Microsoft PowerToys est une collection d'utilitaires qui optimisent la productivité et la personnalisation sous Windows.
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103,2 k • +41 aujourd'hui • Script Vim)
Une version dérivée de Vim axée sur l'extensibilité et la facilité d'utilisation.
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58,7 k • +74 aujourd'hui • C#)
Le système de gestion de médias de logiciels libres : serveur et API.
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52,7 k • +23 aujourd'hui • Python)
LlamaIndex est une plateforme de traitement de documents pour l'IA.
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9,8 k • +14 aujourd'hui • Go)
Outil et bibliothèque en ligne de commande pour générer une nomenclature logicielle à partir d'images de conteneurs et de systèmes de fichiers.
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98,7 k • +90 aujourd'hui • TypeScript)
Playwright est un framework pour les tests et l'automatisation web. Il permet de tester Chromium, Firefox et WebKit avec une API unique.
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61,6 k • +64 aujourd'hui • TypeScript)
🔥🔥🔥 Alternative open source à Jira, Linear, Monday et ClickUp. Plane est une plateforme moderne de gestion de projet permettant de gérer les tâches, les sprints, la documentation et le triage.
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23,5 k • +17 aujourd'hui • C)
Outil open source de recherche de similarité vectorielle pour Postgres
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━
Abonnez-vous à @devrepos pour découvrir chaque jour les dépôts GitHub les plus ...
[hi] बेहतरीन डेवलपर स्टैक: 23 ट्रेंडिंग GitHub रिपोज़ | 28-10-2026 | डेव रिपोज़ डेली
cutt.ly
🔥 इस नए AI रिपॉजिटरी के बारे में आपको किसी ने नहीं बताया (ग्रीष्म 2027 - इंटर्नशिप)
ओपन सोर्स इकोसिस्टम की नवीनतम जानकारी के लिए GitHub के इन चुनिंदा रिपॉजिटरी का इस्तेमाल करें। इनोवेटिव डेवलपर टूल्स से लेकर क्रांतिकारी फ्रेमवर्क तक, ये वो प्रोजेक्ट हैं जो सॉफ्टवेयर जगत में धूम मचा रहे हैं।
28 अक्टूबर, 2026
इस वीडियो में क्या है:
- आज प्राप्त स्टार रेटिंग के आधार पर शीर्ष 23 ट्रेंडिंग GitHub रिपॉजिटरी
- प्रत्येक प्रदर्शित रिपॉजिटरी के लिए डेवलपर अंतर्दृष्टि और प्रोजेक्ट अवलोकन
- प्रत्येक ओपन सोर्स प्रोजेक्ट का AI-नैरेटेड वॉकथ्रू
- आसान पहुँच के लिए नीचे सभी रिपॉजिटरी के सीधे लिंक
⏱️ टाइमस्टैम्प (YouTube अध्याय):
00:00 - परिचय: आज के उच्च-प्रभाव वाले उपकरण
00:09 - ट्रेंडिंग लीडरबोर्ड अवलोकन
00:25 - #1 समर 2027 इंटर्नशिप
00:54 - #2 n8n
01:24 - #3 datahub
01:45 - #4 upscayl
02:08 - #5 फ्री-फॉर-डेव
02:33 - #6 शानदार रिमोट जॉब
02:59 - #7 डेटा साइंस फॉर बिगिनर्स
03:27 - #8 पॉवर टॉयज़
03:50 - #9 नेओविम
04:10 - #10 जेलीफिन
04:33 - #11 लामा_इंडेक्स
04:56 - #12 सिफ्ट
05:18 - #13 प्लेराइट
05:46 - #14 प्लेन
06:09 - #15 पीजीवेक्टर
06:28 - #16 ऑसम
06:59 - #17 रनर-इमेजेज
07:19 - #18 रस्टडेस्क
07:43 - #19 लेज़ीगिट
08:05 - #20 ट्रांसफॉर्मर्स
08:31 - #21 डायरेक्टस
09:02 - #22 गिटलीक्स
09:22 - #23 ओपनकोर-लेगेसी-पैचर
09:45 - आउट्रो और कुंजी मुख्य बिंदु
━━━━━━━━━━━━━━━━━━━━━━━━
आज के शीर्ष 23 ट्रेंडिंग रिपॉजिटरी:
━━━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Summer2027-इंटर्नशिप (⭐ 48.2k • आज +21 • पायथन)
ग्रीष्मकालीन 2027 के लिए सॉफ्टवेयर इंजीनियरिंग, डेटा साइंस, एआई, क्वांट, प्रोडक्ट मैनेजमेंट और हार्डवेयर इंटर्नशिप के अवसर। Simplify और Pitt CSC द्वारा प्रतिदिन अपडेट किया जाता है।
🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208.9k • आज +161 • TypeScript)
नेटिव AI क्षमताओं वाला फेयर-कोड वर्कफ़्लो ऑटोमेशन प्लेटफ़ॉर्म। विज़ुअल बिल्डिंग को कस्टम कोड के साथ मिलाएं, सेल्फ-होस्ट या क्लाउड का उपयोग करें, 400+ इंटीग्रेशन उपलब्ध हैं।
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12.9k • आज +10 • Python)
आपके डेटा और AI स्टैक के लिए कॉन्टेक्स्ट प्लेटफ़ॉर्म
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51.2k • आज +76 • TypeScript)
🆙 Upscayl - Linux, MacOS और Windows के लिए नंबर 1 मुफ़्त और ओपन सोर्स AI इमेज अपस्केलर।
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2k • आज +55 • HTML)
SaaS, PaaS और IaaS सेवाओं की एक सूची जिनमें DevOps और InfraDevelop के लिए उपयोगी निःशुल्क विकल्प उपलब्ध हैं।
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50k • आज +99 • अज्ञात)
शानदार रिमोट जॉब्स और संसाधनों की एक चुनिंदा सूची। vinta/awesome-python से प्रेरित
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • आज +47 • Jupyter Notebook)
10 सप्ताह, 20 पाठ, सभी के लिए डेटा साइंस!
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140.1k • आज +84 • C)
Microsoft PowerToys यूटिलिटीज़ का एक संग्रह है जो Windows पर उत्पादकता और अनुकूलन को बढ़ाता है।
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103.2k • आज +41 • Vim Script)
विस्तारशीलता और उपयोगिता पर केंद्रित Vim-फोर्क
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58.7k • आज +74 • C#)
फ्री सॉफ्टवेयर मीडिया सिस्टम - सर्वर बैकएंड और API
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52.7k • आज +23 • Python)
LlamaIndex एक AI-आधारित दस्तावेज़ प्रसंस्करण प्लेटफ़ॉर्म है।
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9.8k • आज +14 • Go)
कंटेनर इमेज और फ़ाइल सिस्टम से सॉफ़्टवेयर बिल ऑफ़ मैटेरियल्स जनरेट करने के लिए एक CLI टूल और लाइब्रेरी।
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98.7k • आज +90 • TypeScript)
Playwright वेब टेस्टिंग और ऑटोमेशन के लिए एक फ़्रेमवर्क है। यह एक ही API के साथ Chromium, Firefox और WebKit की टेस्टिंग की सुविधा देता है।
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61.6k • आज +64 • TypeScript)
🔥🔥🔥 ओपन-सोर्स Jira, Linear, Monday और ClickUp का विकल्प। Plane एक आधुनिक प्रोजेक्ट मैनेजमेंट प्लेटफॉर्म है जिसका उपयोग टास्क, स्प्रिंट, डॉक्स और ट्राइएज को मैनेज करने के लिए किया जाता है।
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23.5k • आज +17 • C)
पोस्टग्रेस के लिए ओपन-सोर्स वेक्टर समानता खोज
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━━━
दैनिक GitHub ट्रेंडिंग रिपॉजिटरी, ओपन सोर्स राउंडअप और डेवलपर समाचारों के लिए @devrepos को सब्सक्राइब करें।
GitHub पर सर्वश्रेष्ठ ओपन सोर्स सॉफ़्टवेयर और ट्रेंडिंग प्रोजेक्ट्स को कवर करने वाले नए वीडियो हर दिन देखें।
[id] Tumpukan Perangkat Lunak Pengembang Terbaik: 23 Repositori GitHub Terpopuler | 28-10-2026 | Dev R...
cutt.ly
🔥 Belum Ada yang Memberitahu Anda Tentang Repositori AI Baru Ini (Magang Musim Panas 2027)
Tetap terhubung dengan ekosistem open source dengan pilihan repositori GitHub yang sedang tren ini. Dari alat pengembang yang inovatif hingga kerangka kerja yang inovatif, ini adalah proyek-proyek yang sedang membuat gebrakan di komunitas perangkat lunak saat ini.
28 Oktober 2026
Isi video ini:
- 23 repositori GitHub terpopuler yang diurutkan berdasarkan bintang yang diperoleh hari ini
- Wawasan pengembang dan ikhtisar proyek untuk setiap repositori unggulan
- Panduan yang dinarasikan AI untuk setiap proyek sumber terbuka
- Tautan langsung ke semua repositori di bawah ini untuk akses mudah
⏱️ CAP WAKTU (Bab YouTube):
00:00 - Pendahuluan: Alat-alat Berdampak Tinggi Hari Ini
00:09 - Ikhtisar Papan Peringkat Terpopuler
00:25 - #1 Magang Musim Panas 2027
00:54 - #2 n8n
01:24 - #3 datahub
01:45 - #4 upscayl
02:08 - #5 free-for-dev
02:33 - #6 awesome-remote-job
02:59 - #7 Ilmu Data untuk Pemula
03:27 - #8 PowerToys
03:50 - #9 neovim
04:10 - #10 jellyfin
04:33 - #11 llama_index
04:56 - #12 syft
05:18 - #13 playwright
05:46 - #14 plane
06:09 - #15 pgvector
06:28 - #16 awesome
06:59 - #17 runner-images
07:19 - #18 rustdesk
07:43 - #19 lazygit
08:05 - #20 transformers
08:31 - #21 directus
09:02 - #22 gitleaks
09:22 - #23 OpenCore-Legacy-Patcher
09:45 - Outro & Key Poin Penting
━━━━━━━━━━━━━━━━━━━━━━━
23 REPOSITORI YANG SEDANG TREN HARI INI:
━━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Summer2027-Internships (⭐ 48,2 ribu • +21 hari ini • Python)
Lowongan magang musim panas 2027 di bidang rekayasa perangkat lunak, ilmu data, AI, kuantitatif, manajemen produk, dan perangkat keras. Diperbarui setiap hari oleh Simplify dan Pitt CSC.
🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208,9 ribu • +161 hari ini • TypeScript)
Platform otomatisasi alur kerja fair-code dengan kemampuan AI asli. Gabungkan pembuatan visual dengan kode kustom, hosting sendiri atau cloud, 400+ integrasi.
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12.9k • +10 hari ini • Python)
Platform Konteks untuk Tumpukan Data dan AI Anda
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51.2k • +76 hari ini • TypeScript)
🆙 Upscayl - Pengoptimal Gambar AI Gratis dan Sumber Terbuka #1 untuk Linux, MacOS, dan Windows.
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2k • +55 hari ini • HTML)
Daftar penawaran SaaS, PaaS, dan IaaS yang memiliki tingkatan gratis yang menarik bagi devops dan infradev
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 hari ini • Tidak diketahui)
Daftar pilihan pekerjaan dan sumber daya jarak jauh yang luar biasa. Terinspirasi oleh vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 hari ini • Jupyter Notebook)
10 Minggu, 20 Pelajaran, Ilmu Data untuk Semua!
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140.1k • +84 hari ini • C)
Microsoft PowerToys adalah kumpulan utilitas yang meningkatkan produktivitas dan kustomisasi di Windows
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103.2k • +41 hari ini • Skrip Vim)
Vim-fork yang berfokus pada ekstensibilitas dan kegunaan
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58.7k • +74 hari ini • C#)
Sistem Media Perangkat Lunak Gratis - Backend Server & API
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52.7k • +23 hari ini • Python)
LlamaIndex adalah platform pemrosesan dokumen untuk AI
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9.8k • +14 hari ini • Go)
Alat dan pustaka CLI untuk menghasilkan Daftar Material Perangkat Lunak dari citra kontainer dan sistem file
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98.7k • +90 hari ini • TypeScript)
Playwright adalah kerangka kerja untuk Pengujian dan Otomatisasi Web. Ini memungkinkan pengujian Chromium, Firefox, dan WebKit dengan satu API.
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61.6k • +64 hari ini • TypeScript)
🔥🔥🔥 Alternatif Jira, Linear, Monday, dan ClickUp sumber terbuka. Plane adalah platform manajemen proyek modern untuk mengelola tugas, sprint, dokumen, dan triase.
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23.5k • +17 hari ini • C)
Pencarian kesamaan vektor sumber terbuka untuk Postgres
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━━
Berlangganan @devrepos untuk repositori GitHub yang sedang tren setiap hari, rangkuman sumber terbuka, dan berita pengembang.
Video baru setiap hari yang membahas perangkat lunak sumber terbuka terbaik dan proyek-proyek yang sedang tren di GitHub.
[it] Lo stack definitivo per sviluppatori: 23 repository GitHub di tendenza | 28/10/2026 | Dev Repos D...
Italiano: cutt.ly
🔥 Nessuno ti ha parlato di questo nuovo repository di IA (Tirocini estivi 2027)
Rimani aggiornato sull'ecosistema open source con questa selezione accurata di repository GitHub di tendenza. Da strumenti di sviluppo innovativi a framework rivoluzionari, questi sono i progetti che stanno facendo scalpore nella comunità del software in questo momento.
28 ottobre 2026
Contenuto del video:
- I 23 repository GitHub più popolari, classificati in base alle stelle guadagnate oggi
- Approfondimenti per sviluppatori e panoramiche dei progetti per ogni repository presentato
- Guida interattiva con narrazione AI per ogni progetto open source
- Link diretti a tutti i repository qui sotto per un facile accesso
⏱️ INDICE DEI CONTENUTI (Capitoli di YouTube):
00:00 - Introduzione: Strumenti di grande impatto di oggi
00:09 - Panoramica della classifica dei più popolari
00:25 - #1 Summer2027-Internships
00:54 - #2 n8n
01:24 - #3 datahub
01:45 - #4 upscayl
02:08 - #5 free-for-dev
02:33 - #6 awesome-remote-job
02:59 - #7 Data-Science-For-Beginners
03:27 - #8 PowerToys
03:50 - #9 neovim
04:10 - #10 jellyfin
04:33 - #11 llama_index
04:56 - #12 syft
05:18 - #13 playwright
05:46 - #14 plane
06:09 - #15 pgvector
06:28 - #16 awesome
06:59 - #17 runner-images
07:19 - #18 rustdesk
07:43 - #19 lazygit
08:05 - #20 transformers
08:31 - #21 directus
09:02 - #22 gitleaks
09:22 - #23 OpenCore-Legacy-Patcher
09:45 - Outro e Key Punti chiave
━━━━━━━━━━━━━━━━━━━━━━━━
I 23 REPOSITORY PIÙ DI TENDENZA DI OGGI:
━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Summer2027-Internships (⭐ 48.2k • +21 oggi • Python)
Offerte di stage per l'estate 2027 in ingegneria del software, data science, IA, analisi quantitativa, gestione del prodotto e hardware. Aggiornato quotidianamente da Simplify e Pitt CSC.
#1 SimplifyJobs/Summer2027-Internships (⭐ 48.2k • +21 oggi • Python)
Offerte di stage per l'estate 2027 in ingegneria del software, data science, IA, analisi quantitativa, gestione del prodotto e hardware. 🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208.9k • +161 oggi • TypeScript)
Piattaforma di automazione del flusso di lavoro con codice equo e funzionalità native di IA. Combina la creazione visuale con codice personalizzato, self-hosting o cloud, oltre 400 integrazioni.
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12.9k • +10 oggi • Python)
La piattaforma di contesto per il tuo stack di dati e IA
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51.2k • +76 oggi • TypeScript)
🆙 Upscayl - Il miglior strumento gratuito e open source per l'upscaling di immagini basato sull'IA per Linux, MacOS e Windows.
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2k • +55 oggi • HTML)
Un elenco di offerte SaaS, PaaS e IaaS con piani gratuiti di interesse per DevOps e InfraDev
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 oggi • Sconosciuto)
Un elenco curato di fantastiche offerte di lavoro da remoto e risorse. Ispirato da vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 oggi • Jupyter Notebook)
10 settimane, 20 lezioni, Data Science per tutti!
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140.1k • +84 oggi • C)
Microsoft PowerToys è una raccolta di utilità che potenziano la produttività e la personalizzazione su Windows
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103.2k • +41 oggi • Vim Script)
Fork di Vim focalizzato su estensibilità e usabilità
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58.7k • +74 oggi • C#)
Il sistema multimediale software libero - Backend server e API
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52.7k • +23 oggi • Python)
LlamaIndex è la piattaforma di elaborazione documenti per l'IA
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9.8k • +14 oggi • Go)
Strumento e libreria CLI per la generazione di una distinta base software da immagini container e filesystem
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98.7k • +90 oggi • TypeScript)
Playwright è un framework per il test e l'automazione web. Consente di testare Chromium, Firefox e WebKit con un'unica API.
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61.6k • +64 oggi • TypeScript)
🔥🔥🔥 Alternativa open source a Jira, Linear, Monday e ClickUp. Plane è una moderna piattaforma di gestione progetti per gestire attività, sprint, documentazione e priorità.
#14 makeplane/plane (⭐ 61.6k • +64 oggi • TypeScript)
🔥🔥🔥 Un'alternativa open source a Jira, Linear, Monday e ClickUp. Plane è una moderna piattaforma di gestione progetti per gestire attività, sprint, documentazione e priorità.
#14 makeplane/plane (⭐ 61.6k • +64 oggi • TypeScript)
🔥🔥🔥 Un'alternativa open source a Jira, Linear, M...
[iw] הסטאק האולטימטיבי למפתחים: 23 פרויקטי GitHub חמים | 28/10/2026 | Dev Repos Daily
cutt.ly
🔥 אף אחד לא סיפר לכם על מאגר הבינה המלאכותית החדש הזה (קיץ 2027 - התמחויות)
הישארו מעודכנים במערכת האקולוגית של קוד פתוח עם מבחר נבחר זה של מאגרי GitHub טרנדיים. מכלי פיתוח חדשניים ועד מסגרות פורצות דרך, אלו הפרויקטים שעושים גלים בקהילת התוכנה כרגע.
28 באוקטובר, 2026
מה יש בסרטון הזה:
- 23 מאגרי GitHub הטרנדיים ביותר מדורגים לפי כוכבים שנצברו היום
- תובנות מפתחים וסקירות פרויקטים עבור כל מאגר מומלץ
- סיור מקיף על כל פרויקט קוד פתוח באמצעות בינה מלאכותית
- קישורים ישירים לכל המאגרים למטה לגישה נוחה
⏱️ חותמות זמן (פרקי YouTube):
00:00 - מבוא: הכלים בעלי ההשפעה הגבוהה של היום
00:09 - סקירת טבלת המובילים הטרנדיים
00:25 - #1 קיץ 2027 - התמחויות
00:54 - #2 n8n
01:24 - #3 datahub
01:45 - #4 upscayl
02:08 - #5 free-for-dev
02:33 - #6 awesome-remote-job
02:59 - #7 Data-Science-For-Beginners
03:27 - #8 PowerToys
03:50 - #9 neovim
04:10 - #10 jellyfin
04:33 - #11 llama_index
04:56 - #12 syft
05:18 - #13 playwright
05:46 - #14 plane
06:09 - #15 pgvector
06:28 - #16 awesome
06:59 - #17 runner-images
07:19 - #18 rustdesk
07:43 - #19 lazygit
08:05 - #20 transformers
08:31 - #21 directus
09:02 - #22 gitleaks
09:22 - #23 OpenCore-Legacy-Patcher
09:45 - סיום וסולם נקודות חשובות
━━━━━━━━━━━━━━━━━━━━━━━
23 המאגרים הטרנדיים ביותר של היום:
━━━━━━━━━━━━━━━━━━━━━━━
#1 SimplifyJobs/Kitchen2027-Internships (⭐ 48.2k • +21 היום • Python)
פרסומי התמחויות בהנדסת תוכנה, מדעי נתונים, בינה מלאכותית, כימות, ניהול מוצר וחומרה בקיץ 2027. מתעדכנים מדי יום על ידי Simplify ו-Pitt CSC.
🔗 SimplifyJobs/Summer2027-Internships
#2 n8n-io/n8n (⭐ 208.9k • +161 היום • TypeScript)
פלטפורמת אוטומציה של זרימת עבודה בקוד הוגן עם יכולות בינה מלאכותית מקוריות. שלב בנייה ויזואלית עם קוד מותאם אישית, אירוח עצמי או ענן, 400+ אינטגרציות.
🔗 n8n-io/n8n
#3 datahub-project/datahub (⭐ 12.9k • +10 היום • Python)
פלטפורמת ההקשר עבור מחסנית הנתונים והבינה המלאכותית שלך
🔗 datahub-project/datahub
#4 upscayl/upscayl (⭐ 51.2k • +76 היום • TypeScript)
🆙 Upscayl - #1 משדרג תמונות בינה מלאכותית חינמי וקוד פתוח עבור לינוקס, MacOS ו-Windows.
🔗 upscayl/upscayl
#5 ripienaar/free-for-dev (⭐ 140.2k • +55 היום • HTML)
רשימה של הצעות SaaS, PaaS ו-IaaS שיש להן שכבות חינמיות שמעניינות מפתחי פיתוח ופיתוח אינפרא-אדום
🔗 ripienaar/free-for-dev
#6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 היום • לא ידוע)
רשימה אוצרת של עבודות ומשאבים מדהימים מרחוק. בהשראת vinta/awesome-python
🔗 lukasz-madon/awesome-remote-job
#7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 היום • Jupyter Notebook)
10 שבועות, 20 שיעורים, מדעי נתונים לכולם!
🔗 microsoft/Data-Science-For-Beginners
#8 microsoft/PowerToys (⭐ 140.1k • +84 היום • C)
Microsoft PowerToys הוא אוסף של כלי עזר שמשפרים את הפרודוקטיביות וההתאמה האישית ב-Windows
🔗 microsoft/PowerToys
#9 neovim/neovim (⭐ 103.2k • +41 היום • סקריפט Vim)
Vim-fork המתמקד בהרחבה ושימושיות
🔗 neovim/neovim
#10 jellyfin/jellyfin (⭐ 58.7k • +74 היום • C#)
מערכת המדיה של תוכנה חופשית - שרת Backend ו-API
🔗 jellyfin/jellyfin
#11 run-llama/llama_index (⭐ 52.7k • +23 היום • Python)
LlamaIndex היא פלטפורמת עיבוד מסמכים עבור בינה מלאכותית
🔗 run-llama/llama_index
#12 anchore/syft (⭐ 9.8k • +14 היום • Go)
כלי וספרייה של ממשק שורת פקודה (CLI) ליצירת רשימת חומרים של תוכנה מתמונות של מכולות ומערכות קבצים
🔗 anchore/syft
#13 microsoft/playwright (⭐ 98.7k • +90 היום • TypeScript)
Playwright היא מסגרת לבדיקות אינטרנט ואוטומציה. היא מאפשרת בדיקת Chromium, Firefox ו-WebKit עם API יחיד.
🔗 microsoft/playwright
#14 makeplane/plane (⭐ 61.6k • +64 היום • TypeScript)
🔥🔥🔥 אלטרנטיבה בקוד פתוח ל-Jira, Linear, Monday ו-ClickUp. Plane היא פלטפורמת ניהול פרויקטים מודרנית לניהול משימות, ספרינטים, מסמכים וטראז'.
🔗 makeplane/plane
#15 pgvector/pgvector (⭐ 23.5k • +17 היום • C)
חיפוש דמיון וקטורי בקוד פתוח עבור Postgres
🔗 pgvector/pgvector
━━━━━━━━━━━━━━━━━━━━━━━━
הירשמו ל-@devrepos לקבלת מאגרי GitHub יומיים פופולריים, סיכומים בקוד פתוח וחדשות מפתחים.
סרטונים חדשים מדי יום המכסים את תוכנות הקוד הפתוח הטובות ביותר ופרויקטים פופולריים ב-GitHub.
[ja] 究極の開発者スタック:GitHubでトレンドのレポジトリ23選 | 2026年10月28日 | 開発者レポジトリ・デイリー
cutt.ly
🔥 誰も教えてくれなかった、注目のAIリポジトリ(2027年夏期インターンシップ)
厳選された話題のGitHubリポジトリで、オープンソースエコシステムの最新情報を常に把握しましょう。革新的な開発ツールから画期的なフレームワークまで、ソフトウェアコミュニティで今まさに注目を集めているプロジェクトをご紹介します。
2026年10月28日
この動画の内容:
- 本日獲得したスター数でランキングされた、GitHubで話題のリポジトリ上位23件
- 各リポジトリの開発者向け解説とプロジェクト概要
- AIによるナレーション付き、各オープンソースプロジェクトの解説
- すべてのリポジトリへの直接リンク(下記参照)
⏱️ タイムスタンプ(YouTubeチャプター):
00:00 - はじめに:今日の注目ツール
00:09 - トレンドランキング概要
00:25 - #1 Summer2027-Internships
00:54 - #2 n8n
01:24 - #3 datahub
01:45 - #4 upscayl
02:08 - #5 free-for-dev
02:33 - #6 awesome-remote-job
02:59 - #7 Data-Science-For-Beginners
03:27 - #8 PowerToys
03:50 - #9 neovim
04:10 - #10 jellyfin
04:33 - #11 llama_index
04:56 - #12 syft
05:18 - #13 playwright
05:46 - #14 plane
06:09 - #15 pgvector
06:28 - #16 awe
9 views
已有 Postgres 的项目做语义检索,可看看开源 pgvector:向量与业务数据放在同一库,支持 SQL 过滤和关联查询。需安装扩展,另选嵌入模型生成向量。先用精确检索作基准;HNSW 等近似索引能提速,但会牺牲召回,带过滤条件时尤其要检查结果是否足量。 pgvector/pgvector
11 views
From Rows to Vectors: pgvector inside Postgres
---
title: "From Rows to Vectors: pgvector inside Postgres"
published: true
description: "What a vector database does, how HNSW and IVFFlat work, and the traps of running pgvector inside the Postgres you already run."
tags: postgres, pgvector, node, ai
---
Say your product needs search that understands meaning. A user types "the tax due when you sell shares at a profit" and expects the page on capital gains tax, even though none of those words appears in its title. The usual next step is a new piece of infrastructure: Pinecone, Qdrant, Milvus or Weaviate, with its own bill, its own SLA and a sync job to keep it in step with your real data.
There is another option: keep the embeddings in pgvector, inside the PostgreSQL database you already run. This article explains what a vector database does, how its indexes work, and what to watch for when you run one inside Postgres, including the traps that are easy to ship without noticing.
---
Two kinds of questions
A relational database answers "which rows are equal to this?"
SELECT * FROM orders WHERE customer_id = 42;
The answer is exact. A row matches, or it does not.
A vector database answers "which rows are like this?"
SELECT id, body FROM documents
ORDER BY embedding <=> $1
LIMIT 5;
The answer is a ranking. Every row sits some distance away from the query, and you ask for the closest few. Everything else in this article follows from that one change of contract.
| | Relational database | Vector database |
| --- | --- | --- |
| Stores | rows of typed columns | vectors, plus metadata |
| Asks | equal, range, join | the k nearest to a query vector |
| Index | B-tree, hash: exact lookups | HNSW, IVF: approximate search |
| Answer | an exact set of rows | a ranked list that may miss a few |
| Built for | transactions, constraints, joins | similarity over millions of vectors |
| Examples | PostgreSQL, MySQL | Pinecone, Qdrant, Milvus, Weaviate |
pgvector puts the right-hand column inside the left-hand one.
---
From meaning to numbers
An embedding model turns a piece of content into a fixed-length list of numbers. It is trained so that similar meanings produce similar numbers. OpenAI's text-embedding-3-small returns 1,536 numbers by default, and text-embedding-3-large returns 3,072. Both accept a dimensions parameter to return fewer (OpenAI embeddings guide).
Two properties matter in practice:
- Fixed length. ** A single word and a full page produce the same number of dimensions.
- One model for both sides. ** Stored rows and incoming queries must go through the same model, with the same settings. Swap the model and every stored vector needs re-embedding.
Meaning as a place
Picture those numbers as coordinates. Real embeddings have 1,536 axes, but two are enough to get the idea. "cat", "dog" and "puppy" land close together. "pizza", "pasta" and "bread" form their own cluster. "capital gains tax", "CGT" and "tax on a share sale" sit in a third.
Search becomes geometry. Embed the query with the same model, then ask for its nearest neighbours. A query for "kitten" finds "cat" and "puppy", although "kitten" is a different word from both. No keyword matching is involved.
"Near" needs a definition
pgvector ships several distance operators (pgvector README, Querying):
| Operator | Distance | What it measures |
| --- | --- | --- |
| <-> | L2 (Euclidean) | the straight-line gap between the two points |
| <=> | cosine | the angle between the vectors; length is ignored |
| <#> | negative inner product | angle and length, negated so that smaller means closer |
| <+> | L1 (taxicab) | the sum of the per-axis differences |
| <~>, <%> | Hamming, Jaccard | for binary (bit) vectors |
> Note: <#> returns the negative inner product because Postgres only supports ascending-order index scans on operators (pgvector README, Getting Started). Multiply by -1 if you want the real value.
The pgvector README states that OpenAI embeddings are normalised to length 1, and recommends inner product for best performance on normalised vectors (pgvector README, Exact Search). For unit-length vectors, inner product ranks results in the same order as cosine.
---
Why a B-tree can't help
A B-tree handles equality and range queries on data that can be sorted into an order (PostgreSQL docs, Index Types). WHERE id = 42 takes a few hops down the tree and lands on the row.
"Nearest to this vector" has no fixed order. Every query has its own centre, so nothing can be sorted in advance. Without an approximate index, pgvector performs exact nearest neighbour search: it compares the query against every row (pgvector README, Indexing).
The cost adds up quickly. Take one million rows of 1,536-dimensional vectors:
- 1.5 billion multiply-adds per query (1,000,000 × 1,536).
- About 6.2 GB read per query. ** pgvector stores each vector in 4 × dimensions + 8 bytes, so 6,152 bytes per row (pgvector README, Vector Type).
Exact search returns perfect recall, and its cost grows in a straight line with the table.
Approximate nearest neighbours
Vector indexes give up a little accuracy to stop reading everything. The measure for that accuracy is recall: the share of the true k nearest neighbours that actually come back.
Two things follow:
- Recall is a dial. ** Each index type has a query-time setting that trades speed for recall. You choose where to sit on the curve.
- Adding an index can change your results. The pgvector README says it directly: you will see different results for queries after adding an approximate index (pgvector README, Indexing). A test that passed against a sequential scan can fail the day the index ships.
---
IVFFlat: cluster first, then search a few clusters
IVFFlat divides the vectors into lists, each grouped around a centroid, and a query searches only the lists closest to it. The number of lists it searches is probes, and the default is 1 (pgvector README, IVFFlat). The lists come from k-means over the rows present at build time; the index build reports a performing k-means phase.
The weakness is at the borders. If the true nearest neighbour sits just over the edge of a neighbouring list, a query with probes = 1 never looks there.
The README gives these starting points:
- lists = rows / 1000 for up to 1M rows, and sqrt(rows) above that.
- probes = sqrt(lists).
- Create the index after the table has some data.
CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
SET ivfflat.probes = 10;
The README's troubleshooting section names the symptom too: an IVFFlat index created with too little data for its number of lists returns fewer results (pgvector README, Troubleshooting).
An easy way to hit this. ** Indexes usually arrive through migrations, and migrations usually run before any data exists. An IVFFlat index created that way builds its lists from an empty table. Leave probes at its default, and every query searches one list out of 100. The fix is a REINDEX once the data is loaded, and an explicit SET ivfflat.probes per query. Better still, use HNSW, which has no training step.
---
HNSW: a layered graph
HNSW (Hierarchical Navigable Small World) comes from a paper by Malkov and Yashunin (arXiv 1603.09320). It builds a graph in layers. The top layer has few nodes and long links; each layer below has more nodes and shorter links, down to layer 0, which holds every vector. A search starts at the top, hops to whichever neighbour is closer to the query, drops a layer, and repeats.
Its settings and their defaults (pgvector README, HNSW):
- m = 16: the maximum number of connections per layer.
- ef_construction = 64: the size of the candidate list while building.
- hnsw.ef_search = 40: the size of the candidate list per query. This is the recall dial.
HNSW has no training step, so you can create it on an empty table.
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops);
SET hnsw.ef_search = 100;
Builds are much faster when the graph fits in maintenance_work_mem, and Postgres prints a notice when it no longer does (pgvector README, Index Build Time).
---
Choosing between them
All rows below come from the pgvector README.
| | HNSW | IVFFlat |
| --- | --- | --- |
| Structure | multilayer graph | lists around centroids |
| Training | none: can build on an empty table | k-means: build after loading |
| Build | slower, more memory | faster, less memory |
| Speed vs recall | better | lower |
| Query dial | hnsw.ef_search, default 40 | ivfflat.probes, default 1 |
| Build dials | m = 16, ef_construction = 64 | lists |
My default is HNSW, unless build time or memory is the constraint. It gives a better speed-recall trade-off, and it removes the empty-table trap entirely.
---
pgvector: a vector database inside Postgres
pgvector is an open-source Postgres extension; the README's install instructions reference version 0.8.7 at the time of writing (pgvector README, Installation). It adds vector types, distance operators and the two index types above. Everything you already rely on stays: ACID transactions, joins, point-in-time recovery, replication and the query planner. On AWS, Aurora PostgreSQL supports it (AWS announcement: pgvector 0.8.0 on Aurora PostgreSQL).
CREATE EXTENSION vector;
---
Types and limits
One 1,536-dimension embedding takes this much space in each type. Storage formulas and index limits come from the pgvector README reference and its HNSW section.
| Type | Element | Bytes for 1,536 dims | Index up to |
| --- | --- | --- | --- |
| vector | float32 | 6,152 (4 × d + 8) | 2,000 dims |
| halfvec | float16 | 3,080 (2 × d + 8) | 4,000 dims |
| bit | 1 bit, lossy | 200 (d ÷ 8 + 8) | 64,000 dims |
| sparsevec | non-zero elements only | 8 × non-zero + 16 | 1,000 non-zero, HNSW only |
Vectors can store up to 16,000 dimensions; only indexing is limited. A 3,072-dimension model such as text-embedding-3-large cannot be indexed as vector, but it can be indexed as halfvec (pgvector README FAQ).
> Note: bit keeps only one bit per dimension. Use it as a fast first pass and re-rank with the full vector (see scaling below).
A table, an index, a query
CREATE TABLE documents (
id bigserial PRIMARY KEY,
body text NOT NULL,
embedding vector(1536) NOT NULL
);
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops);
-- the five nearest to a query vector
SET hnsw.ef_search = 100;
SELECT id, body FROM documents
ORDER BY embedding <=> $1
LIMIT 5;
Four details that cost people time:
- The dimension is part of the column type. A vector(1536) column holds 1,536-dimensional vectors; to mix dimensions, you need the unsized vector type (pgvector README FAQ).
- The index serves one distance function. The README says to add an index for each distance function you want to use (pgvector README, HNSW). An index built with vector_cosine_ops speeds up <=> only.
- hnsw.ef_search is per session. Use SET LOCAL inside a transaction to change it for one query (pgvector README, Query Options).
- The index needs both ORDER BY and LIMIT, and the ORDER BY must be the distance operator itself in ascending order. ORDER BY 1 - (embedding <=> $1) DESC skips the index (pgvector README, Troubleshooting).
Why cosine here, after I said inner product is fastest? For unit-length vectors, the two give identical rankings, and cosine stays correct if a future model does not normalise its output. I chose safety over a small speed gain.
The same query from Node.js
The pgvector npm package supports node-postgres, Knex.js, Kysely, Prisma, Drizzle ORM and several other libraries (pgvector-node README).
npm install pgvector pg openai
import OpenAI from 'openai'
import pg from 'pg'
import pgvector from 'pgvector/pg'
const question = 'the tax due when you sell shares at a profit'
const client = new pg.Client()
await client.connect()
await pgvector.registerTypes(client)
// reads OPENAI_API_KEY from the environment
const { data } = await new OpenAI().embeddings.create({
model: 'text-embedding-3-small',
input: question,
})
const { rows } = await client.query(
`SELECT id, body FROM documents
ORDER BY embedding <=> $1 LIMIT 5`,
[pgvector.toSql(data[0].embedding)],
)
Where each part comes from:
- registerTypes and toSql follow the pgvector-node README, node-postgres section. With a pool, call registerTypes in the pool's onConnect hook.
- registerType (singular) is deprecated since pgvector-node 0.3.0 (pgvector-node README, Upgrading).
- new OpenAI() reads OPENAI_API_KEY from the environment (openai-node README).
- The response's data array holds one item per input, each with an embedding field (OpenAI API reference, Create embeddings).
---
Production trap 1: WHERE runs after the index scan
This one bites quietly. With an approximate index, filtering is applied after the index is scanned.
The pgvector README gives the numbers: if a condition matches 10% of rows, HNSW with the default ef_search of 40 leaves only about 4 matching rows on average (pgvector README, Filtering). Ask for 10, and you get about 4. No error, no warning: just fewer results.
-- asks for 10, typically gets about 4 back once an HNSW index exists
SELECT id, body FROM documents
WHERE course_id = 123
ORDER BY embedding <=> $1
LIMIT 10;
Since pgvector 0.8.0, iterative index scans fix this (pgvector CHANGELOG). When enabled, the scan keeps reading the index until enough results are found, or until it reaches hnsw.max_scan_tuples (default 20,000) or ivfflat.max_probes (pgvector README, Iterative Index Scans).
SET hnsw.iterative_scan = strict_order;
-- or, trading exact ordering for recall:
SET hnsw.iterative_scan = relaxed_order;
-- IVFFlat supports relaxed ordering only
SET ivfflat.iterative_scan = relaxed_order;
Other options from the README: an index on the filter column for conditions that match a low percentage of rows, a partial index when you filter by a few distinct values, and partitioning when you filter by many (pgvector README, Filtering). For tenant isolation, it recommends list partitioning or separate tables (pgvector README, Multitenancy).
Why this one survives code review. ** A filtered similarity query on a table with no vector index returns exact results, because Postgres scans everything. The day someone adds an index for speed, the same query starts returning fewer rows, with no error. A test that runs against a small, unindexed table will not catch it. If you filter, decide on iterative scans before you add the index.
---
Production trap 2: keywords and meaning need each other
Vector search misses exact identifiers. Search for a course code or a regulation number and the embedding treats it as noise. Full-text search has the opposite gap: it misses paraphrases. Hybrid search runs both and merges the results. The pgvector README suggests combining it with Postgres full-text search, using Reciprocal Rank Fusion or a cross-encoder to merge (pgvector README, Hybrid Search).
The merge is the hard part, because the scores live on different scales. Cosine distance and ts_rank cannot be added together. Reciprocal Rank Fusion (RRF) sidesteps that by combining positions instead of scores. The constant k smooths the score so that a first place does not dominate:
score(doc) = Σ 1 / (k + rank)
With k = 50, the default rrf_k in Supabase's hybrid search guide:
| Doc | Full-text rank | Vector rank | RRF score |
| --- | --- | --- | --- |
| A | 2 | 1 | 1/52 + 1/51 = 0.0388 |
| B | 1 | 3 | 1/51 + 1/53 = 0.0385 |
| C | not ranked | 2 | 1/52 = 0.0192 |
| D | 3 | not ranked | 1/53 = 0.0189 |
Documents A and B appear in both lists, so they rise to the top. A document that only one method found still scores, just lower.
In Postgres, both halves live in the same table. Keep a tsvector column next to the vector column, run the two ranked queries as CTEs, and join them on the document ID. Supabase's guide shows a complete SQL function built this way.
---
Production trap 3: scaling before you buy
The usual argument for a dedicated vector store is scale. Before taking on another service, pull the Postgres levers first. The README lists them (pgvector README, Scaling); the order is mine:
1. halfvec columns. Half the bytes per vector, so a smaller working set.
2. Binary quantization for the index, then re-rank the shortlist at full precision.
3. maintenance_work_mem large enough for HNSW to build in memory.
4. A bigger instance: more memory, CPU and storage.
5. Read replicas, then Citus or PgDog to shard.
The binary quantisation pattern, adapted from the README:
CREATE INDEX ON documents
USING hnsw ((binary_quantize(embedding)::bit(1536)) bit_hamming_ops);
SELECT * FROM (
SELECT * FROM documents
ORDER BY binary_quantize(embedding)::bit(1536) <~> binary_quantize($1)
LIMIT 20
) shortlist
ORDER BY embedding <=> $1
LIMIT 5;
A dedicated store earns its place when those levers are pulled, and your recall or latency targets still miss, or when vector traffic has to scale independently of the transactional database.
I looked for an independent benchmark that names the size where Postgres stops being enough, and did not find one. Measure recall and latency on your own data before deciding. The README shows how: compare approximate results with exact search by running the query with SET LOCAL enable_indexscan = off (pgvector README, Monitoring).
---
When you don't need an index at all
Not every vector table needs an approximate index. Two common shapes:
- Few-shot examples for an LLM. ** You pick the most similar past examples to put in a prompt. These tables are often small, so exact search with no index is fast enough, and it gives perfect recall for free.
- A document library for retrieval. Uploaded documents are chunked and embedded, with a full-text column beside each vector, ready for hybrid search. This is the shape that grows, and where the index decisions above start to matter.
Start without an index, measure latency, and add one when the numbers ask for it. When you do, revisit every filtered query first.
---
Three things to take home
1. A vector database answers "like this". Embeddings turn meaning into distance; nearest neighbours turn distance into results.
2. Approximate means a dial. ef_search and probes trade speed for recall. Treat the defaults as a starting point and tune from there.
3. Start in Postgres; earn the next database. pgvector keeps vectors beside the rows they describe, in a system you already back up, monitor and understand. Measure recall and latency before adding a service to run.
And you? Did you start with a dedicated vector store, or keep everything in Postgres? If you have hit a recall or latency wall with pgvector, I would like to know the table size and the setting that broke it. Drop a comment if you have questions.
Bruno Souza, Software Engineer
---
Sources
- pgvector README: types, operators, HNSW, IVFFlat, filtering, iterative scans, hybrid search, scaling, monitoring
- pgvector CHANGELOG: 0.7.0 types, 0.8.0 iterative scans
- pgvector-node README: Node.js usage, supported libraries, 0.3.0 upgrade notes
- OpenAI embeddings guide: model dimensions and the dimensions parameter
- OpenAI API reference, Create embeddings: response shape
- openai-node README: client construction and API key
- PostgreSQL docs, Index Types: what a B-tree handles
- Malkov and Yashunin, Efficient and robust approximate nearest neighbour search using Hierarchical Navigable Small World graphs
- Supabase docs, hybrid search: RRF with rrf_k = 50
- AWS: pgvector 0.8.0 support in Aurora PostgreSQL
Facts checked on 20 October 2026.
1 reaction
はじめてのインデータベースAI~ベクトル検索・RAGからAIエージェントまで~
はじめに
この記事は 2026/10/21 の Oracle AI Jam Session #41 はじめてのインデータベースAI~ベクトル検索・RAGからAIエージェントまで~ にてご紹介させていただいたものです。
<iframe width="560" height="315" src="youtube.com" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
生成AIを業務で活用するには、社内ナレッジや業務データを安全かつ適切に検索し、回答やアクションにつなげる仕組みが必要です。本記事では、データベースの中でベクトル検索によるセマンティック・サーチ、埋め込みモデルによるベクトル生成、検索拡張生成、自然言語によるデータ照会、AIエージェントを実現する「インデータベースAI」の考え方を、初学者にも分かる全体像とコード例・デモを通じて紹介します。初学者の方だけでなくデータベースの専門家としてのスキルやキャリアを活かして AI 活用への取り組みをお考えのベテラン・エンジニアの方にもお役に立てる内容を目指しています。
oracle-code-tokyo-dev.connpass.com
ご紹介するコードや環境構築手順は GitHubリポジトリで公開しています。ぜひ、実際に動かして体験してみてください。
kutsushitaneko/orajam41-in-database-ai-demo
「管理画面が開きません!どうしたらいいですか?見に来てくれますか?」
!サーバールームの電話対応
「保守登録番号DEV001のラックサーバーで、管理画面が開かない。最初に何を確認すればよいですか?現地保守を頼めますか?」
!AIアシスタントと保守確認-2.png
こんな問い合わせに答えるには、製品のマニュアルだけでなく、そのサーバーの保守契約も必要ですね。
!AIでつなぐ保守対応-3.png
一般的な対処法を知っているAIでも、社内の最新マニュアルや顧客の契約を参照しなければ、この問い合わせへの答えを出すことはできません。つまり、AI を本格的に業務利用するためには AI に 業務データを活用させてあげることが必要です。
!AI の業務利用で大切なこと
一方で、AI、特に、人に代わって自律的に仕事を進めてくれる AI エージェントに大切な業務データへのアクセスを許可することにはリスクが伴います。
!AI の業務利用で心配なこと
そこで、業務データを管理している場所で、AIに必要な検索や処理を実行するという考え方が出てきます。
!データのあるところへAIを持っていく
この記事では、 「データのあるところへAIを持っていく」 という考え方を、サーバー機器メーカーの保守問い合わせ窓口の顧客対応を例に見ていきます。意味的な類似性に基づいて文書を探すところから始め、根拠付きの回答、契約の照会、複数の処理を使うAIエージェントへと進みます。
この記事の読者想定は、SELECT・WHERE・JOINなどのデータベースの基礎を知っている方です。AIの予備知識は不要です。実装例にはAutonomous AI Database 26aiを使いますが、検索・生成・業務処理の役割分担は他の構成にも応用できると思います。
この記事は以下のような構成になっています。
| 章 | 内容 | デモ |
|---|---|---|
| 第1章 | 文書の意味検索と、業務データの照会を組み合わせる | — |
| 第2章 | 埋め込みモデルをDB内へ持ち込み、SQLでベクトルを作る | ベクトル基礎 |
| 第3章 | チケットの顧客と機種を絞って、ベクトル検索する | A:意味検索 |
| 第4章 | 検索した文書を根拠に、RAGで回答する | B:RAG |
| 第5章 | NL2SQL で契約情報を照会する | C:NL2SQL |
| 第6章 | 文書検索と契約照会をAgentのツールにする | D:Agent |
記事中の実行用コードは動作確認済みです。手元で再現する場合は、先に末尾のAppendixでユーザー作成から環境を準備してください。コードとデータ生成器はこちらです。
1. 文書の意味検索と業務データの照会を組み合わせる
一つの問い合わせに性質の異なる二つの問いがある
この記事では、メーカーの保守担当者がラックサーバーの問い合わせに対応する場面を考えていきます。
顧客は保守登録番号DEV001のサーバーについて、「管理画面が開かない。確認手順を知りたい。現地保守も頼めるか」と問い合わせてきています。
:::note warn
登場する企業・機種・保守手順は、すべて本記事用の架空のものです。
:::
- 「何を確認すればよいか」 は、症状に関連するマニュアルや保守手順 を探す問いです。
- 一方、「現地保守を頼めるか」 は、そのサーバーの契約状態・有効期間・サービス範囲 を確かめる問いです。同じ製品機種でも、契約によって対応できる内容は異なるという想定です。
flowchart LR
Q["管理画面が開かない。<br>どうしたらいい?<br>現地保守を頼める?"]
Q --> P["症状に合う手順は?"]
Q --> C["この1台の契約で対応できる?"]
P --> D["マニュアルなどの文書で<br>意味の近い記述を検索"]
C --> R["データベースの契約表で<br>契約状態・期間・範囲を照合"]
D --> A["根拠のある確認手順と<br>対応案を提示"]
R --> A
- 上段は、マニュアルや保守手順書といった 非構造化データの意味検索(セマンティックサーチ) が適した問い
- 下段は、契約表(テーブル)のような リレーショナルデータベースの検索 を必要とする問い
これから先は、まずは意味検索、次に根拠付きの文章生成、契約情報への自然言語照会、最後にそれらを使うエージェントへと見ていきます。
ベクトル検索は文字の一致だけでは拾えない候補も探してくれる
「管理画面が開かない」や「管理画面が固まった」、「管理画面が応答しない」は、同じ文字列ではありませんが関連する症状です。
「管理画面が開かない」という症状の訴えに対して、「管理画面が固まった」や「管理画面が応答しない」という症状について書かれているドキュメントを見つける必要がありますが、キーワード検索ではこれらのドキュメントを見つけられない可能性があります。
そこで、意味検索(セマンティックサーチ)が必要になります。つまり、意味的に近いドキュメントを見つける検索です。このような検索を実現する技術にベクトル検索があります。
!image.png
- 埋め込みモデルという機械学習モデルで、テキストや画像の特徴を反映したベクトル(数値の列)を生成します
- ベクトル間の距離が近いもの同士は元のデータの特徴が似ている、距離が遠いものは似ていないということになります
!image.png
ベクトル検索の処理概要
!文書と質問を同じモデルでベクトル化して比較する
- 製品マニュアルなどのドキュメントをベクトルに変換してデータベースへ格納
- 「管理画面が開かないけど、どうしたらいい?」などの質問文も 同じ埋め込みモデル でベクトルへ変換
- データベースのドキュメント・ベクトルの中で質問文のベクトルに距離的に近いものを探します
:::note
ベクトル間の距離指標
- 距離の指標には、コサインやユークリッド距離など様々なものがあります。
- 距離指標は、埋め込みモデルの学習方法や公開されている推奨設定に合わせて選びます。
- 一般的に利用されている埋め込みモデルではコサインが使われていることが多いようです。
:::
:::note warn
チャンキング
- テキストを埋め込みモデルでベクトル化する際には、1つのベクトルに変換できるテキストの長さには制限があります。
- ドキュメントなどをこの制限内に収まるように分割することを チャンキング と呼び、細分化されたテキストの断片を チャンク と呼びます。
- この記事では、簡略化のため短いドキュメントを用意して、1ドキュメント=1チャンクとしています。
:::
意味の類似性で探すドキュメントとリレーショナルデータで管理される業務上の契約条件を同じDBで扱う
症状がよく似ていても、別機種の手順や別顧客専用の文書を案内してはいけません。意味の近さに加えて、「誰の問い合わせか」「どの機種か」「公開済みか」といった条件が必要になります。ここで、顧客・サーバー・契約などのリレーショナルデータが役立ちます。
一般的な検索アプリケーションでは、検索画面に「機種」「地域」「公開区分」などの絞り込み項目が用意されています。こうした絞り込みの切り口を、ファセットと呼びます。値ごとの件数を表示し、選んだ属性で候補を絞る使い方が典型です。
ベクトルDBでも、文書に付けたメタデータを使ってフィルタリングできるようになっています。例えばQdrantは、payloadという付加情報のフィルターと、属性値ごとの件数を返すfacetingを提供しています。Qdrantのpayloadとfaceting
製品に関する単純な仕様質問なら、文書のメタデータに対する model=AX-100 のようなフィルタ条件で十分です。一方、今回のシナリオのような「対応中のチケットの顧客が契約しているサーバーの機種」「現在公開中で、その顧客が閲覧できる文書」のような条件は、契約や権限の変更に追随する必要があります。
このような業務データは、リレーショナルデータベースで管理されていることが多いかと思います。ベクトルDBのメタデータによるフィルタリングだけでこれらの条件を判定するには、判定に必要な情報をメタデータやタグとして複製し、契約や権限の変更に合わせて更新する必要があります。
業務表とベクトルが同じリレーショナルデータベースにあれば、検索用に複製したメタデータやタグの更新を待たず、元の表をJOINやEXISTSで参照して条件を表現できます。
| 条件・運用上の課題 | RDB内のベクトル検索で使える仕組み | この記事のコード例とのつながり |
|---|---|---|
| 製品ドキュメントだけでは顧客や契約の関係が分からない | JOIN・EXISTSで複数の表の関係を条件にする | 顧客、契約、サーバー、文書を同じDBで照会する |
| 契約終了や公開取消をすぐ反映したい | 元データを参照するビューとトランザクション | 閲覧用ビューが顧客範囲・公開状態を反映する |
| 日付や件数を含む条件が必要 | 日付比較、GROUP BY、HAVINGなどのSQL | 契約の有効期間や機種別の対象数を判定する |
| 検索経路ごとにアクセス管理を増やしたくない | DB権限、ビュー、構成に応じた行制御や監査 | SQL検索とPL/SQLツールで同じ閲覧範囲を使う |
この利点はOracleだけのものではありません。PostgreSQLのpgvectorもJOINやトランザクションと組み合わせられます。MySQLにも、SQLで埋め込み生成や類似検索を提供するMySQL HeatWaveがあります。pgvector、MySQL HeatWaveのベクトル生成と検索
Oracleでは、リレーショナル表とベクトルに加え、JSONや全文検索、地理空間情報、グラフなども同じデータ基盤で扱えます。業務データの種類ごとに検索用の別システムを増やす前に、既存DBのデータとSQLをどこまで使えるかを考えられます。
:::note
こんなことも SQL 1つで実行できます
!image.png
:::
データを複製すると検索以外の仕事も増える
!image.png
AIアプリケーションを作るとき、業務DBから文書や契約を取り出し、別の検索基盤へ複製する構成はよく使われます。
この構成には、検索処理を独立して拡張できる利点があります。一方、契約更新をいつ反映するか、削除済み文書をどう消すか、顧客ごとの閲覧範囲をどう同期するか、という仕事も発生します。
例えば、業務DBで契約が解約されたのに、ベクトルDBなど、AIで利用するために複製したデータが昨日のままなら、検索自体が正しくても誤った案内につながります。顧客が契約を解約したり、保守窓口担当者が異動するなど文書の閲覧権限が変更された場合も同様です。必要なのは、似た文章を探す能力だけではありません。 どの時点の情報を、誰の権限で使っているか を制御できる構成です。
Oracleが示す「データのあるところへAIを持っていく」という方向性は、業務データの近くで意味検索や推論を実行し、既存のデータ管理と組み合わせるものです。AI Vector Searchでは、ベクトルを業務表と同じDBに保存し、SQLから統合的に扱うことができます。Oracle AI Vector Search
ただし、同じDBに置くだけで鮮度や権限が自動的に正しくなるわけではありません。本文を更新したら対応するベクトルも更新する必要があります。検索に使うビューや実行ユーザーの権限も設計します。DB経験者が行ってきたデータ整合性・権限・運用の設計が、ここでも必要になります。
2. 埋め込みモデルをDB内へ持ち込み、DBの中でベクトルを作る
前章では、文書のベクトルと業務データを同じDBで扱う意義を見ました。次に、そのベクトルを作る埋め込みモデルの配置場所を考えます。
埋め込みモデルは外部サービスに置くか、DB内に置くか
ベクトル検索を組み立てるとき、一般的な構成の一つは、外部のクラウドサービスに埋め込みを依頼する方式です。アプリケーションから文書や質問をAPIへ送り、返されたベクトルをDBへ保存したり、検索に使ったりします。例えばOCI Generative AIも、文章をベクトルへ変換するAPIを提供しています。外部サービスでの埋め込み生成
!image.png
Oracle AI Database では、埋め込みモデルをデータベースにインポートして、データベースの中でベクトル化する構成を取ることもできます。
!image.png
ここで、ちょっと先走りですが、ベクトル検索結果を元に自然文で回答を生成する RAG(検索拡張生成)における埋め込みモデルと回答生成用LLMに渡すデータの範囲を比べてみます。
ベクトルデータベースにデータを投入する際には、 ベクトル化の対象に選んだ文書の全チャンク 、つまり、文書全体を、埋め込みモデルへ順次入力します。一方、RAG回答生成では、検索で取得した少数のチャンクを質問と一緒にLLMへ渡します。RAGの準備と質問時の流れ
| 場面 | 埋め込みモデルへ渡すデータ | LLM へ渡すデータ |
|---|---|---|
| 初回の埋め込み生成 | 検索対象文書の全チャンク | なし |
| 文書の追加・改訂 | 追加・変更したチャンク | なし |
| 質問の埋め込み生成 | 質問文 | なし |
| RAGの回答生成 | なし | 質問と取得した文書抜粋 |
つまり、外部の埋め込みAPIを使うと、検索対象の文書をすべて外部へ送ることになります。
埋め込みモデルをデータの近くへ配置する動機はここにあります。文書全体の移動を抑えながら、外部LLMへは回答に必要な箇所を選んで渡せるためです。
データベースによっては、対応する埋め込みモデルを内部へインポートし、SQLから実行できるものがあります。
Oracle AI Databaseでは、対応するONNX形式のモデルをDB内のランタイムで実行します。ONNXは機械学習モデルの標準フォーマットです。DB内での埋め込み生成
| 観点 | 外部の埋め込みサービスを利用 | 対応モデルをDB内へインポート |
|---|---|---|
| データの移動 | 文書・質問を外部APIへ送信 | 埋め込みのための外部API送信を省ける |
| 推論の運用 | サービス側が推論基盤を管理。利用可能なモデルから選ぶ | モデルの取得・変換・ロード・更新を管理する |
| 資源と費用 | API利用料・利用上限を考慮。推論負荷をDBから分離できる | DBのCPU・メモリーを使い、他のDB処理との競合を考慮する |
| レイテンシー | 推論時間に加え、通信やサービス側の待ち時間がかかる | APIとの往復を省けるが、モデルやDB資源によって推論時間は変わる |
DB内実行のメリットは、データの移動を減らし、SQLから埋め込みと検索を扱えることです。その代わり、大きなモデルのメモリー消費や同時実行数もDBの運用として考慮する必要があります。
また、一般にクラウドサービスの埋め込みモデルはGPU 上で稼働していますが、データベースにインポートする場合は CPU で稼働することとなりますので単純に「DB内だからネットワーク遅延最小で速い」「外部APIだからネットワーク遅延があって遅い」ということにはなりません。
速度が問題となるような場合には、データベースの近くで稼働する推論環境へオフロードするということも考えられます。Oracle AI Database の場合は、Private AI Services Container という仕組みも提供しています。
:::note
回答生成の際にも外部の LLM にデータを送信したくない場合には、LLM をオンプレミスでセルフホスティングしたり、クラウドの専用クラスターサービスの利用や自社テナント(アカウント)内でセルフホスティングすることも考えられます。
:::
今回はインデータベースAIの実例として、OSS の埋め込みモデル multilingual-e5-large をDB内にインポートします。文書と質問の両方をこの埋め込みモデルでベクトル化します。文章の回答やSQLを生成するLLMは、別のモデルです。こちらは外部のOCI Enterprise AI(Generative AI)の LLM を利用します。 埋め込みモデルはDB内、生成用LLMはDB外 という配置を、処理の流れに沿って確認しましょう。
処理の配置を図に示します。左側では文書のベクトル化、意味検索、契約の照会をDB内で行います。右側の生成用LLMはDBの外にあります。線に添えた情報が外部へ渡る情報です。
!DB内の検索・推論と外部LLMへ渡す情報
| 処理 | 今回の実行場所 | 使う情報 |
|---|---|---|
| 文書・質問の埋め込み | DB内のmultilingual-e5-large | 文書本文・質問 |
| 距離検索、絞り込み、契約判定 | DBのSQL/PL/SQL | ベクトル・機種・契約・閲覧範囲 |
| RAGの回答生成 | DB内のPL/SQLから外部LLMを呼ぶ | 質問・機種・取得した文書抜粋 |
| SQL生成 | NL2SQLの処理から外部LLMを呼ぶ | 質問・対象ビューのメタデータなど |
| Agentの実行 | DB側の制御と外部LLMの判断を組み合わせる | 指示・ツール定義・ツール実行結果など |
生成用LLMはOCI Enterprise AI(Generative AI) サービスのxai.grok-4.3をシカゴリージョンで利用し、DBは東京のAutonomous AI Database 26aiです。DBからAPIを呼ぶ場合も、渡した情報はDBの外へ出ます。「すべてのAI処理がDB内で完結する」という構成ではありません。何をDB内で処理し、何を外へ送るかを選ぶことが設計の要点です。
ここからは、埋め込みモデルの取り込みと、DB内でベクトルを生成・検索する小さなデモを見ます。
ONNXモデルをObject StorageからDBへ取り込む
準備の流れは、対応するONNX形式へ変換したモデルをObject Storageに置き、DBからDBMS_VECTOR.LOAD_ONNX_MODEL_CLOUDというPL/SQLプロシージャを呼ぶ、というものです。今回のモデルは重みが外部ファイルに分かれているため、.onnxだけでなく、付属する.jsonと.dataも同じ配置先へ置きます。DBからObject Storageへの認証にはリソースプリンシパルを使います。
ユーザー・権限・リソースプリンシパルの設定を完了した後、次のSQLを実行すると、埋め込みモデルをデータベースへインポートできます。URIはモデルの配置先へ置き換えてください。
BEGIN
DBMS_VECTOR.LOAD_ONNX_MODEL_CLOUD(
model_name => 'MULTILINGUAL_E5_LARGE',
credential => 'OCI$RESOURCE_PRINCIPAL',
uri => 'https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/<bucket>/o/<prefix>/multilingual_e5_large.onnx',
metadata => JSON('{"function":"embedding","embeddingOutput":"embedding","input":{"input":["DATA"]}}')
);
DBMS_VECTOR.INMEMORY_ONNX_MODEL(
model_name => 'MULTILINGUAL_E5_LARGE', enable => TRUE);
END;
/
このインポート処理が完了した後のベクトル検索では、VECTOR_EMBEDDINGというSQL関数で今登録した埋め込みモデルを呼び出してDB内でベクトル化を実行します。
なお、大きなモデルでは重みのメモリー共有も設定します。変換と配置の詳細はmultilingual-e5-largeのインポート手順、APIの引数はLOAD_ONNX_MODEL_CLOUDを参照してください。このデモで使う準備スクリプトはsql/setup/10_load_embedding_model.sqlで、ユーザー作成からの手順はAppendix A〜Cにまとめています。
データベース内の埋め込みモデルでベクトル化してみる
手元で試す際にはAppendixの準備を済ませ、変更していなければ ORAJAM41USERというユーザーで接続してください。ここで紹介する SQL はsql/demos/00b_embedding_basics.sqlでも公開しています。
埋め込みモデルが登録されていることを確認してみます
SELECT model_name, mining_function, algorithm, external_data, inmemory
FROM user_mining_models
WHERE model_name='MULTILINGUAL_E5_LARGE';
user_mining_models は、Oracle AI Database で「現在のユーザーが所有している機械学習モデル」を一覧表示するデータ・ディクショナリ・ビューです。モデル名、用途、アルゴリズム、作成日時などを確認できます。
<details>
<summary>実行結果:登録済みモデル</summary>
| MODEL_NAME | MINING_FUNCTION | ALGORITHM | EXTERNAL_DATA | INMEMORY |
|---|---|---|---|---|
| MULTILINGUAL_E5_LARGE | EMBEDDING | ONNX | YES | YES |
</details>
- EMBEDDING は、埋め込みモデルであることを表しています。
- EXTERNAL_DATA は、ALGORITHM = 'ONNX' の場合、インメモリー共有を有効化できるモデルかを示す。YES:有効化可能、NO:不可。ONNX以外では意味を持たず、NO が設定される。RU 23.26.1 以降。
- INMEMORY は、ALGORITHM = 'ONNX' かつ EXTERNAL_DATA = 'YES' の場合、インメモリー共有が有効かを示す。YES:有効、NO:無効。それ以外では意味を持たず、NO が設定される。RU 23.26.1 以降。
:::note
EXTERNAL_DATA = 'YES' は「外部の推論APIを使う」という意味ではありません
ONNXの external data は、重み(Weight、パラメータ)などの初期化データ(initializers)を、メインのONNXモデルファイルとは別のファイルに分離して保持する仕組みです。Oracleでは、この外部初期化データを持つモデルについて、初期化データを共有メモリーに一度ロードし、複数セッションで共有できます。したがって、EXTERNAL_DATA = 'YES' は「外部の推論APIを使う」という意味ではありません。
:::
質問を1件だけベクトルへ変換してみます
今回使う multilingual-e5-large は、検索する質問と検索対象の文書を接頭辞で区別するように学習されています。そのため、検索用途では埋め込みを生成する直前に、文書の先頭へpassage: 、質問の先頭へquery: を付けます。これはこのモデルの入力仕様で、日本語の文章にも同じ英語の接頭辞を使います。詳しい使い分けはモデルカードのUsageとFAQを参照してください。
長文は埋め込みモデルの入力データ(トークン)長の上限を踏まえて分割します。この記事のデモでは短い文書を使います。
SELECT VECTOR_EMBEDDING(
MULTILINGUAL_E5_LARGE
USING 'query: 管理画面が固まって操作できない' AS data
) AS embedding FROM dual;
<details>
<summary>実行結果:生成されたベクトルの先頭8要素</summary>
[0.03598599, 0.00471110, -0.01730750, -0.02658993, 0.02554353, -0.02953884, 0.00086610, 0.10251307, ...]
全1024要素のうち先頭8要素を小数点以下8桁で表示し、残りを省略しています。SQLクライアントではベクトルのセルを開いて確認できます。
</details>
生成されたベクトルの次元数を確認します
SELECT VECTOR_DIMENSION_COUNT(
VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE
USING 'query: 管理画面が固まって操作できない' AS data)
) AS dimensions FROM dual;
| DIMENSIONS |
|---|
| 1024 |
1024次元とは数値の個数です。各次元が「契約」「障害」といった人が認識するような特徴を表しているわけではありません。そのため、「10番目の次元は何か?」ということは説明できません。また、同じデータでも埋め込みモデルごとに全く異なるベクトルに変換されます(ベクトル空間が異なる)ので、同じ1024次元ベクトルであっても、別のモデルで生成したベクトルを混ぜて比較することはできません。
データベース内の埋め込みモデルでベクトル検索してみる
ドキュメントを格納するチャンク表(OJ41_CHUNKS)には、本文のテキスト(chunk_text列)と、ベクトル(embedding列)の両方を保存しています。
ベクトルは、原文をそのまま復元するための保存形式ではありません。検索後に本文を表示したり、LLMへ根拠として渡したりするため、元の本文テキスト(chunk_text)も保持します。
チャンク表(OJ41_CHUNKS)の主要な列だけを取り出すと次の構造になっています。説明用に省略したDDLなので、試す際にはこのまま実行せず、表の作成には35_create_demo_tables.sqlを使ってください。
-- 説明用:主要列のみ。制約・管理列などは省略。
CREATE TABLE OJ41_CHUNKS (
chunk_id VARCHAR2(24),
doc_id VARCHAR2(20),
chunk_text VARCHAR2(2400 CHAR),
embedding VECTOR(1024, FLOAT32)
);
なお、データの生成・投入と文書のベクトル化は、[Appendix C「デモデータとAI定義を準備する」](#c-デモデータとai定義を準備する)の手順に従って実施してください。以下の検索SQLは、その準備を済ませてから実行します。
この記事ではシンプルに短い16のサンプル文書をそれぞれ1チャンクにしています。
全16件の文書ID、本文の先頭100文字、ベクトルの次元数を確認してみましょう。別機種の文書や廃止済み・未公開の文書も含めたデモデータの全体です。
SELECT chunk_id, doc_id, SUBSTR(chunk_text, 1, 100) AS chunk_text_preview,
VECTOR_DIMENSION_COUNT(embedding) AS dimensions
FROM OJ41_CHUNKS
ORDER BY doc_id;
<details>
<summary>実行結果:全16チャンク(本文は先頭100文字)</summary>
| CHUNK_ID | DOC_ID | CHUNK_TEXT_PREVIEW | DIMENSIONS |
|---|---|---|---|
| KB001-01 | KB001 | 管理画面が応答しないとき<br>AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。次に管理端末から疎通を確認し、障害ログを保存します。業務への影響を確認せずに | 1024 |
| KB002-01 | KB002 | E101:温度上昇の確認<br>AX-100でE101が表示された場合は吸気口の閉塞と室温を確認します。吸気口の前を空け、温度と発生時刻を記録します。装置の分解は行わず、警告が続く場合は保守窓口へ連絡します | 1024 |
| KB003-01 | KB003 | E201:電源系統の警告<br>AX-100のE201は電源系統の警告です。電源ケーブルの接続と施設側の給電状況を確認し、ログを保存します。電源ユニットの交換は作業資格と契約の確認後に手配します。 | 1024 |
| KB004-01 | KB004 | 管理画面停止時の旧手順<br>旧手順ではAX-100の管理画面が停止したら直ちに再起動する案内でした。この文書は廃止済みです。現行手順KB001を使用してください。 | 1024 |
| KB005-01 | KB005 | 管理画面が応答しないとき<br>BX-200の管理画面が応答しない場合は、管理ポートの状態と証明書の期限を確認します。AX-100とは確認箇所が異なります。ログ取得後、管理サービスの復旧方法を保守窓口へ確認 | 1024 |
| KB006-01 | KB006 | E101:認証設定の確認<br>BX-200のE101は認証設定の不整合を示します。時刻同期と認証サーバー設定を確認します。AX-100の同じコードは温度警告であり、この手順を適用しません。 | 1024 |
| KB007-01 | KB007 | 通信が途切れるとき<br>AX-100で通信が断続的に切れる場合は、ケーブル損傷、リンク状態、接続先スイッチのエラー数を確認します。時刻をそろえたログを取得し、設定変更前後を比較します。 | 1024 |
| KB008-01 | KB008 | ログの保存方法<br>AX-100の管理画面で「保守」から「ログ出力」を選択します。ファイル名と取得時刻を記録してください。ログには設定値が含まれるため、公開掲示板には添付せず、指定された保守窓口へ渡します | 1024 |
| KB009-01 | KB009 | 設定のバックアップ<br>BX-200の設定変更前には、管理画面のエクスポート機能で設定を保存します。バックアップと変更履歴を対にして保管し、復元作業は機種とソフトウェア版を確認して実施します。 | 1024 |
| KB010-01 | KB010 | ディスク残量の警告<br>CX-300で保存容量の警告が出たら、使用量とログ保持期間を確認します。監査に必要なログを保存してから、承認された保持方針に沿って整理します。無断でファイルを削除しないでください。 | 1024 |
| KB011-01 | KB011 | 時刻のずれを確認する<br>CX-300のイベント時刻がずれる場合は、時刻同期サーバーへの到達性とタイムゾーンを確認します。修正前後の時刻差を記録し、ログを比較するときはその差を考慮します。 | 1024 |
| KB012-01 | KB012 | 顧客C001向け保守連絡手順<br>架空顧客C001では、AX-100の障害ログを収集した後、顧客内の運用責任者へ連絡します。現地訪問は対象機器の有効な契約でONSITEが含まれる場合に手配案を作成します。 | 1024 |
| KB013-01 | KB013 | 顧客C002専用の管理画面復旧手順<br>架空顧客C002のAX-100管理画面停止時には、C002専用の運用手順書に従って責任者へ連絡します。検証用識別語はC002_ONLY_ORCHIDです。この文書は | 1024 |
| KB014-01 | KB014 | 管理画面復旧の検討中手順<br>検討中のAX-100管理画面復旧案です。検証用識別語はDRAFT_ONLY_MAPLEです。未承認のため公開手順として案内してはいけません。 | 1024 |
| KB015-01 | KB015 | 社内担当者用の調査メモ<br>社内限定のAX-100調査メモです。検証用識別語はINTERNAL_ONLY_CEDARです。顧客向け回答の根拠には利用しません。 | 1024 |
| KB016-01 | KB016 | ログ名の特殊文字の扱い<br>ログ名がowner's_logの場合も文字を変更せず記録します。<br>画面の表示例は「温度,電源」と「"警告"」です。CSVへの保存時も改行、カンマ、引用符を保持してください。 | 1024 |
</details>
全16件を質問との距離が近い順に並べ、上位3件を取得します。文書側の埋め込みは準備時に作成済みです。SQL中で今回生成するのは質問側のベクトルです。
- VECTOR_EMBEDDING() SQL 関数で、ベクトルを生成します
- VECTOR_DISTANCE()でベクトル間の距離を計算します。multilingual-e5-largeはコサイン類似度で比較するモデルなので、ここではコサイン距離(1 − コサイン類似度)を使用します。論文:Text Embeddings by Weakly-Supervised Contrastive Pre-training に記載あり
SELECT doc_id, chunk_text,
VECTOR_DISTANCE(embedding,
VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE
USING 'query: 管理画面が固まって操作できない' AS data),
COSINE) AS distance
FROM OJ41_CHUNKS
ORDER BY distance, doc_id
FETCH FIRST 3 ROWS ONLY;
<details>
<summary>実行結果:全16文書に対する近傍上位3件</summary>
| DOC_ID | CHUNK_TEXT | DISTANCE(小数点以下6桁) |
|---|---|---|
| KB001 | 管理画面が応答しないとき<br>AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。次に管理端末から疎通を確認し、障害ログを保存します。業務への影響を確認せずに再起動しないでください。 | 0.132456 |
| KB005 | 管理画面が応答しないとき<br>BX-200の管理画面が応答しない場合は、管理ポートの状態と証明書の期限を確認します。AX-100とは確認箇所が異なります。ログ取得後、管理サービスの復旧方法を保守窓口へ確認します。 | 0.152699 |
| KB004 | 管理画面停止時の旧手順<br>旧手順ではAX-100の管理画面が停止したら直ちに再起動する案内でした。この文書は廃止済みです。現行手順KB001を使用してください。 | 0.153947 |
</details>
質問の「固まって」に対して、KB001「管理画面が応答しないとき」が先頭になりました。2位のKB005も管理画面の不応答を扱いますが、機種はBX-200です。3位のKB004は廃止済みの旧手順です。症状に近い文書でも、そのまま顧客への案内に使えるとは限りません。
ここまでで、DB内モデルの呼び出し、VECTOR列への保存、距離による並べ替えがつながりました。次はチケットの顧客、サーバーの機種、文書の公開状態を使って、回答に使える文書へ検索範囲を絞ります。
3. チケットの顧客と機種を絞ってベクトル検索する
ここまでは、質問文と似ている(ベクトル間の距離が近い)データを探す検索でした。
ここからは、問い合わせ元の顧客と問題となっているサーバー機種、文書の公開状態で絞り込む検索です。
最初にテーブルとビューの役割を確認し、その構造を使うSQLを順に実行します。
混ぜるな危険!
メーカーの保守担当者が、受付済みのチケットSR001に対応する場面を考えます。
チケットから問い合わせ元の顧客C001を特定し、その顧客のサーバー台帳で保守登録番号DEV001を照合すると、機種がAX-100だと分かります。保守登録番号はメーカーがサーバー1台ごとに発行する番号です。
この対応では、別顧客のサーバーや契約、別顧客専用の文書を混在させてはいけません。また、症状が似ていても別機種の手順を案内しないよう、台帳から取得した機種で検索対象を絞ります。
SR001の対応中に別顧客の保守登録番号を入力しても、そのサーバーや契約は取得できない設計にする必要があります。担当者は全顧客のチケットに対応できますが、1回の照会・回答は選択中のチケットの顧客に限定します。異なる顧客の問い合わせにはその顧客のチケットを開いて対応します。
こんな当たり前のことをなぜここで?
後で紹介するNL2SQL(自然言語の質問からLLMがSQLを生成する仕組み)と関係があるためです。
というのは、NL2SQL では、LLMが顧客条件を付け忘れたり、誤った条件を生成したりする可能性があるため、「この顧客だけを調べて」と指示するだけでは十分ではなくアプリ自体やデータベース側の仕組みでも防御する必要があります。
そこで、アプリが選択したチケットに基づいてDB側のビューで顧客範囲を限定します。この参照経路なら、NL2SQL で生成された SQL が顧客条件を付け忘れても、ビューの外にある別顧客の行を取得してしまうことはありません。
この設計を支えるのが、業務表と文書のベクトルを同じリレーショナルDBで扱えること です。
チケット・顧客・サーバー・契約といった業務データの関係から対象を特定し、さらに文書の公開状態や顧客向けの閲覧範囲を条件にして、ベクトル検索の候補を絞ることができます。
ベクトル検索と業務データを同じデータベースで扱うと、顧客情報や契約情報を検索用の別システムへ複製せずに、業務上の条件で検索対象を絞り込めます。
この記事では、チケットの顧客情報とサーバーの機種情報を使い、その顧客に公開できる、該当機種の文書をベクトル検索します。契約の有効性や現地保守の可否も、同じデータベース内の契約情報を参照して確認します。
対応中のチケットの顧客に検索範囲を限定する仕組み
まず、顧客・サーバー・契約・文書を保存するベース表を確認します。そのうえで、対応中のチケットから顧客を特定し、その顧客に応じた閲覧範囲をビューで制限する仕組みを説明します。
ベース表
ベース表には全顧客の業務データと文書を保存します。チケットを選ぶたびにデータを複製する必要はなく、後述のビューで照会対象を絞ります。
サーバー台帳OJ41_DEVICESでは、device_idが保守登録番号、modelが機種名、serial_noが製造シリアル番号を表します。
次のER図は主要キーの関係です。チケットとサーバーは顧客を介して結び付きます。文書とサーバーは直接の外部キーでは結ばず、機種と公開範囲で照合します。KB012のような顧客専用文書だけが顧客IDを持ちます。
erDiagram
OJ41_CUSTOMERS ||--o{ OJ41_SUPPORT_CASES : customer_id
OJ41_CUSTOMERS ||--o{ OJ41_DEVICES : customer_id
OJ41_DEVICES ||--o| OJ41_CONTRACTS : device_id
OJ41_CUSTOMERS o|--o{ OJ41_KNOWLEDGE : customer_id
OJ41_KNOWLEDGE ||--o{ OJ41_CHUNKS : doc_id
OJ41_SUPPORT_CASES {
string case_id PK
string customer_id FK
}
OJ41_DEVICES {
string device_id PK
string model
string customer_id FK
string serial_no
}
OJ41_CONTRACTS {
string contract_id PK
string device_id FK
string status
date start_date
date end_date
string service_scope
}
OJ41_KNOWLEDGE {
string doc_id PK
string model
string publication
string scope
string customer_id FK
}
OJ41_CHUNKS {
string chunk_id PK
string doc_id FK
string chunk_text
vector embedding
}
実テーブルのDDLはsql/setup/35_create_demo_tables.sql、全データはAppendix Gに掲載しています。
なお、契約が有効期間内であるかどうかといった「現時点」の日付が必要な場合には、システム日付ではなく OJ41_RUN 表の as_of_date 列の日付を使うようにしています。基準日はOJ41_RUNの2026-10-15に固定し、デモコードの実行日によって契約判定が変わらないようにしています。台帳・契約は各12件、文書・チャンクは各16件です。図では基準日を持つOJ41_RUN 表と一部の管理列を省略しています。
閲覧範囲を制限するための仕組み
この仕組みは、対応中のチケットと顧客IDを保持するPL/SQLパッケージ と、その値を使って 行を絞るビューで 構成します。パッケージが「今、どの顧客に対応しているか」を保持し、ビューが「その顧客への回答に使えるデータ」を制約します。
!対応中のチケットの顧客IDをセッション内に保持し、ビューの条件式から参照して閲覧範囲を絞る
対応中のチケットと顧客IDの管理
現在対応しているチケットと顧客IDは、OJ41_CASE_CTXパッケージで管理します。これはこのデモで作成するPL/SQLパッケージです。open_case('SR001')で受付チケット表を引き、顧客C001をセッション内の変数へ保存します。customer_id()がその値を返し、clear_caseが消去します。
| 処理 | 種類 | 役割 | SR001の場合 |
|---|---|---|---|
| open_case('SR001') | プロシージャ | チケット表からチケットIDと顧客IDを取得し、セッション内の変数に保存する | SR001とC001を保存する |
| customer_id() | 関数 | 保存した顧客IDを返す。ビューが顧客範囲を絞るために使う | C001を返す |
| clear_case | プロシージャ | 保存したチケットIDと顧客IDを消去する | 両方をNULLに戻す |
これらはsql/setup/35_create_demo_tables.sqlのOJ41_CASE_CTXのパッケージ本体(PACKAGE BODY)に定義されています。以下は値の保存・読み出し・消去に関係する部分の抜粋です。例外処理と、チケットの切り替えを識別する管理用カウンターは省略しています。
チケットと顧客IDの保存
チケットと顧客IDの値の保存先は、パッケージ本体の非公開変数です。同じパッケージを使っても、値はDBセッションごとに保持されます。
g_case VARCHAR2(20); -- チケットID
g_customer VARCHAR2(10); -- 顧客ID
チケットの対応開始
PL/SQLプロシージャopen_caseは、引数p_case_idで指定したチケットを表から探し、SELECT ... INTOで上記の g_case、g_customer の二つの変数へ値を格納します。実装では、取得前にclear_caseを呼び、前の値を消去しています。
SELECT case_id, customer_id INTO g_case, g_customer
FROM OJ41_SUPPORT_CASES
WHERE case_id = UPPER(p_case_id);
顧客IDの取得
customer_id()は、g_customerに保持した値を返します。ビューは非公開変数を直接読む代わりに、この関数を呼び出します。
FUNCTION customer_id RETURN VARCHAR2 IS
BEGIN
RETURN g_customer;
END;
チケット情報のクリア
clear_caseは、二つの変数をNULLに戻します。処理が終わった接続に、前のチケットの情報を残さないための消去処理です。
PROCEDURE clear_case IS
BEGIN
g_case := NULL;
g_customer := NULL;
END;
DBセッションごとの独立性
チケットIDがSR001のチケットを開くと、そのDBセッションは顧客IDとしてC001を保持します。別のセッションでチケットSR002を開くと、そのセッションが保持する顧客IDはC002になります。一方でclear_caseを実行しても、他方のセッションの値は変わりません。状態は担当者のアカウントではなくDBセッションに属するため、接続プールを使う場合はリクエストごとに設定・消去し、処理が終わるまで同じ接続を別のリクエストへ渡さないようにします。なお、この仕組みは顧客データの混入を減らすもので、担当者がチケットを扱えるかの認可とは異なります。実システムでは別途認可の検討が必要です。
閲覧範囲を制限するビュー
- ビューはOJ41_CASE_CTX.customer_id()が返す顧客IDを使い、ベース表から返す行を絞ります。
- 文書には、顧客IDに加えて公開状態と公開範囲の絞り込み条件も適用します。
前節のベクトル基礎のデモではチャンク表を直接読んでいましたが、ここからは次のビューを使います。
| ビュー | 表から取り出す範囲・付加する情報 | 利用先 |
|---|---|---|
| OJ41_VISIBLE_DEVICES | 対応中のチケットの顧客のサーバー | 保守登録番号と機種の特定 |
| OJ41_VISIBLE_CONTRACTS | 上記サーバーの契約と、有効性・現地保守対象の判定列 | SQL照会、NL2SQL、契約ツール |
| OJ41_VISIBLE_KNOWLEDGE | 公開済みで、共通またはチケット顧客専用の文書 | 文書の閲覧範囲 |
| OJ41_VISIBLE_CHUNKS | 上記文書の本文・ベクトルと機種・タイトル | ベクトル検索、RAG、文書検索ツール |
<details>
<summary>ビューの条件をSQLで読む(説明用抜粋)</summary>
-- 説明用:作成は35_create_demo_tables.sqlで行う。
CREATE OR REPLACE VIEW OJ41_VISIBLE_DEVICES AS
SELECT d.* FROM OJ41_DEVICES d
WHERE d.customer_id = OJ41_CASE_CTX.customer_id();
CREATE OR REPLACE VIEW OJ41_VISIBLE_KNOWLEDGE AS
SELECT k.* FROM OJ41_KNOWLEDGE k
WHERE k.publication = 'PUBLISHED'
AND OJ41_CASE_CTX.current_case() IS NOT NULL
AND (k.scope = 'PUBLIC'
OR (k.scope = 'CUSTOMER'
AND k.customer_id = OJ41_CASE_CTX.customer_id()));
CREATE OR REPLACE VIEW OJ41_VISIBLE_CHUNKS AS
SELECT c.*, k.model, k.title
FROM OJ41_CHUNKS c
JOIN OJ41_VISIBLE_KNOWLEDGE k ON k.doc_id = c.doc_id;
</details>
これらのビューも、前述の35_create_demo_tables.sqlで定義しています。チケットが未選択なら、これらのビューは0件です。文書ではDRAFT・RETIREDとINTERNALを除外します。ここでのINTERNALの除外は顧客向け回答に使う文書の範囲を定めるためで、保守担当者本人の社内閲覧権限を判定しているわけではありません。
:::note info
コラム:ハーネスで、参照できる範囲を制限する
近年のエージェント設計では、モデル呼び出しやツール実行、状態管理、検査など、LLMの周囲の実行を支える仕組みを「ハーネス(harness)」と呼びます。例えばAnthropicは、モデルを呼び出してツールへ処理を振り分けるループをハーネスとして説明しています。ハーネスと実行環境の分担
この観点では、「別顧客を調べないで」とプロンプトに書くことに加え、対応中のチケットに基づくビューと生成SQLの参照先制限で、生成されたSQLが参照する範囲を制限することはハーネスの一種と言えます。これは、LLMが指示を守ることだけに依存せず、実行側にも制約を置く工夫です。ここでは、実行側で「どのデータを参照できるか」を制限しています。次に、契約ルールを使って「どう判定するか」もDB側へ置く方法を見ていきます。所有者ユーザーへの権限制御が別途必要な点は変わりません。
:::
契約の判定も LLM に推測させずビューで判定する
「このサーバーは現地保守の対象か」という問いに答える方法として、契約情報と判定ルールをLLMへ渡して推測(推論)させることが考えられます。例えば、プロンプトで次のように指示する方法です。
> 契約状態がACTIVEで、基準日が契約の開始日から終了日までの範囲内(両端を含む)なら、有効な契約です。さらにサービス範囲がONSITEなら、現地保守の対象と判断してください。
この方法では、条件の読み取りと日付の比較をLLMに任せます。また、NL2SQLに同じルールを伝え、その都度、条件を組み込んだSQLを生成させる方法もあります。
しかし、LLM は間違えることがあります。また、LLM の動作には揺らぎがあり同じ条件でも異なる判定をすることがあります。
決定論的に判定できることはプログラムコードで決定論的に判定すべきです。
今回のデモでは、このルールをDBのビューのCASE式で定義します。
契約表の状態(status)、開始日(start_date)、終了日(end_date)、サービス範囲(service_scope)と基準日(as_of_date)が同じなら、DBのビューは常に同じ判定を返します。
つまり、CASE式でDBに決定論的に判定させる わけです。
判定結果の is_activeは契約の有効性、onsite_eligibleは現地保守の対象かどうかを表し、結果はYまたはNになります。
-- OJ41_VISIBLE_CONTRACTSの計算列を抜粋。cは契約、rは基準日の表。
CASE WHEN c.status = 'ACTIVE'
AND r.as_of_date BETWEEN c.start_date AND c.end_date
THEN 'Y' ELSE 'N' END AS is_active,
CASE WHEN c.status = 'ACTIVE'
AND r.as_of_date BETWEEN c.start_date AND c.end_date
AND c.service_scope = 'ONSITE'
THEN 'Y' ELSE 'N' END AS onsite_eligible
例えば、契約がACTIVEで有効期間内でも、サービス範囲がREMOTEなら、is_activeはY、onsite_eligibleはNです。LLMはこの結果を使って回答し、NL2SQLではonsite_eligible = 'Y'のように判定列を条件にするSQLを生成します。状態・期間・範囲の判定式を毎回生成する必要がなくなります。画面表示やAgentの契約ツールも同じビューを参照すれば、契約ルールをそれぞれに重複して実装せずに済みます。
:::note info
コラム:契約判定をDBへ置くことと、ハーネスの関係
契約判定をビューのCASE式に置く工夫も、ハーネスを支える業務ロジックの一部と捉えられます。LLMの出力には揺らぎや誤りがあり得ますが、契約の可否はDBのビューが決定論的に返す判定値を使います。LLMそのものが決定論的に振る舞うことを期待するのではなく、確定したルールの適用をLLMの外で強制する設計です。
少し冗談めかして言えば、「VIEW as a Harness」 と呼んでもいいかもしれませんね。
:::
なお、この段階では契約が無効な行もビューに残します。期限切れや解約済みの問い合わせにも、「なぜ現地保守の対象ではないか」を説明するためです。第5章のNL2SQLではLLMに有効性の業務ルールを一から判断させず、この判定済みの列を使うSQLを生成させます。
デモA:リレーショナルデータベースによる ベクトル検索 & JOIN & フィルタリング(機種で絞って、ベクトル距離で並べる)
デモAのSQL:sql/demos/01_vector_search.sql
始めに担当者が受付番号SR001を選んだことを、PL/SQL OJ41_CASE_CTX.open_case('SR001') で設定します。
BEGIN OJ41_CASE_CTX.open_case('SR001'); END;
/
open_caseプロシージャは受付チケット表(OJ41_SUPPORT_CASES )から顧客ID(customer_id)を取得して、この接続のチケットコンテキストに保持します。チケットコンテキストとは、現在対応している受付番号・顧客を処理中だけ保持する状態です。
続いて、同じDBセッションで後続のSELECTを実行してください。
SELECT s.case_id, c.customer_id, c.customer_name
FROM OJ41_SUPPORT_CASES s JOIN OJ41_CUSTOMERS c ON c.customer_id=s.customer_id
WHERE s.case_id=OJ41_CASE_CTX.current_case();
この SELECT は、OJ41_CASE_CTX.current_case()で、チケットコンテキストから現在対応している受付番号を取得して、顧客表(OJ41_CUSTOMERS)から顧客ID(customer_id)と顧客名(customer_name)を取得します。
<details>
<summary>実行結果例:選択中の受付チケットと顧客</summary>
| CASE_ID | CUSTOMER_ID | CUSTOMER_NAME |
|---|---|---|
| SR001 | C001 | あおば商事(架空) |
</details>
:::note
Database Actions TIPS
Oracle Database Actionsでは、チケットを設定するPL/SQLと後続のSELECT文をまとめて、1回のスクリプト実行で動かしてください。 同じワークシートでも、文を別々に実行するとチケットの状態は引き継がれません。デモAはsql/demos/01_vector_search.sql全体を実行します。検索ごとに結果を確認する場合は、チケット設定・対象のSELECT・チケット解除を一つのスクリプトにまとめます。Database Actionsのセッション仕様
:::
続けて、その顧客の契約を確認します。OJ41_VISIBLE_CONTRACTS ビューは選択中のチケットの顧客の契約だけを返すビューです。チケット未選択なら0件です。上で SR001 を設定していれば該当する契約の一覧が返るはずです。
SELECT device_id, model, contract_id, status, is_active, onsite_eligible
FROM OJ41_VISIBLE_CONTRACTS
ORDER BY device_id;
<details>
<summary>実行結果例:顧客C001の契約一覧(8件)</summary>
| DEVICE_ID | MODEL | CONTRACT_ID | STATUS | IS_ACTIVE | ONSITE_ELIGIBLE |
|---|---|---|---|---|---|
| DEV001 | AX-100 | CT001 | ACTIVE | Y | Y |
| DEV002 | AX-100 | CT002 | ACTIVE | N | N |
| DEV003 | AX-100 | CT003 | CANCELLED | N | N |
| DEV004 | AX-100 | CT004 | ACTIVE | Y | N |
| DEV005 | AX-100 | CT005 | ACTIVE | Y | Y |
| DEV006 | AX-100 | CT006 | ACTIVE | Y | Y |
| DEV007 | BX-200 | CT007 | ACTIVE | N | N |
| DEV008 | BX-200 | CT008 | ACTIVE | Y | Y |
</details>
A0では、その契約一覧の範囲で保守登録番号DEV001を照合します。
SELECT device_id, model, contract_id, status, is_active, onsite_eligible
FROM OJ41_VISIBLE_CONTRACTS
WHERE device_id = 'DEV001';
<details>
<summary>実行結果例:DEV001の契約と機種</summary>
| DEVICE_ID | MODEL | CONTRACT_ID | STATUS | IS_ACTIVE | ONSITE_ELIGIBLE |
|---|---|---|---|---|---|
| DEV001 | AX-100 | CT001 | ACTIVE | Y | Y |
確かに契約があり、基準日(2026年10月15日)時点で有効で、サーバーの機種は AX-100 で、オンサイト保守も可能であることがわかりました。
</details>
DEV001は契約CT001に対応するAX-100です。別顧客の番号や未登録の番号は取得できません。IS_ACTIVEは契約が基準日に有効ならY、ONSITE_ELIGIBLEは現地保守の対象ならYです。DEV002のような期限切れの契約では、行は取得できてもこれらの値はNになります。
次のA1のベクトル検索では、この結果のAX-100をWHERE句に指定して絞り込みます。
SQLの条件を読み取りやすいように、ここではA0で確認した値AX-100を直接記述しています。
SELECT doc_id, title,
VECTOR_DISTANCE(embedding,
VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE USING 'query: 管理画面が固まって操作できない' AS data), COSINE) AS distance
FROM OJ41_VISIBLE_CHUNKS
WHERE model='AX-100' AND embedding IS NOT NULL
ORDER BY distance, doc_id
FETCH FIRST 3 ROWS ONLY;
<details>
<summary>実行結果例:A1の検索結果3件</summary>
距離は小数点以下6桁に丸めています。
| DOC_ID | TITLE | DISTANCE |
|---|---|---|
| KB001 | 管理画面が応答しないとき | 0.132456 |
| KB008 | ログの保存方法 | 0.193369 |
| KB002 | E101:温度上昇の確認 | 0.196404 |
1位のKB001は管理画面停止の手順です。ベクトル距離が小さい(近い)順に上位3件を取得していますので2位・3位も候補として返りますが、必ずしも質問への回答に役立つデータであるとは限りません。
</details>
このSQLでは、WHEREが対象機種などの業務条件を指定し、VECTOR_DISTANCEが質問との距離を計算します。ORDER BYで近い順に並べ、FETCH FIRSTで上位3件を返します。通常のSQLに「距離」という並べ替え基準が加わったと読むと理解しやすくなります。
ベクトル検索では、KB001「管理画面が応答しないとき」が1位になりました。
それでは、INSTR(chunk_text, '固まって') > 0による部分一致検索だとどうなるでしょうか?
同じ閲覧範囲・機種で、文字列「固まって」を含む文書を探します。
SELECT doc_id, title FROM OJ41_VISIBLE_CHUNKS
WHERE model='AX-100' AND INSTR(chunk_text, '固まって') > 0;
<details>
<summary>実行結果例:A2の部分一致検索</summary>
取得行数: 0件 。
</details>
0件です。
言葉が一致しない場合には部分一致検索では候補を見つけることができませんでしたが、ベクトル検索であれば候補を探せることがわかりました。
デモデータには同じエラーコードE101が機種によって異なる意味を持つ文書も用意しています。
次のA3では機種条件を外し、AX-100の温度上昇とBX-200の認証設定が一緒に返ることを確認します。どちらもE101ですが、対処すべき症状は異なります。ベクトル検索でエラーコードを探せても、対象機種の指定は必要です。
<details>
<summary>オプション・デモA3:機種を絞らずE101を検索した結果</summary>
SELECT doc_id, model, title,
VECTOR_DISTANCE(embedding,
VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE USING 'query: E101の対処は?' AS data), COSINE) AS distance
FROM OJ41_VISIBLE_CHUNKS
WHERE embedding IS NOT NULL
ORDER BY distance, doc_id
FETCH FIRST 3 ROWS ONLY;
| DOC_ID | MODEL | TITLE | DISTANCE |
|---|---|---|---|
| KB002 | AX-100 | E101:温度上昇の確認 | 0.142341 |
| KB006 | BX-200 | E101:認証設定の確認 | 0.148356 |
| KB003 | AX-100 | E201:電源系統の警告 | 0.152087 |
</details>
ここまでのデモで、ビューによる閲覧範囲の制限(現在対応中の顧客に限定)が可能であること、ベクトル検索により異なる表現、言い換えを含む質問で関連文書を取得できること、リレーショナル表の業務データと組み合わせたフィルタリングの有用性がわかりました。
<details>
<summary>参考:別の受付チケットに切り替える</summary>
SR001でDEV009を照会するとビューによる閲覧範囲制限で結果は 0件となるはずですが、 SR002を開くと、その顧客C002のサーバーを照会できます。
BEGIN OJ41_CASE_CTX.open_case('SR002'); END;
/
SELECT device_id FROM OJ41_VISIBLE_DEVICES ORDER BY device_id;
| DEVICE_ID |
|---|
| DEV009 |
| DEV010 |
| DEV011 |
| DEV012 |
C002専用文書KB013はこのチケットで利用でき、C001専用文書KB012は検索対象から外れます。
</details>
このチケットの照会を終えたら、保持した状態を消去します。別顧客のチケットへ移る場合は、例えばopen_case('SR002')で明示的に切り替えます。存在しない受付番号を指定した場合は、古いチケットを消去してエラーにします。
BEGIN OJ41_CASE_CTX.clear_case; END;
/
検索で閲覧範囲制限を考慮した上で質問に対する回答作成に役立つ候補文書を見つけることはできるようになりました。次は、見つけた文書を読んで回答を作る処理を加えます。
4. 検索した文書を根拠にRAG(検索拡張生成)で回答する
根拠に基づいて答えるために、質問のたびに資料を渡す
検索拡張生成(RAG:Retrieval-Augmented Generation)は、質問に関連する情報を検索し、その情報をLLMへ渡して回答を生成する構成です。先ほどの意味検索が、回答の根拠を取り出す部分になります。
!image.png
LLMは自然な文章を作れても、回答が自社の手順や最新の資料に合っているとは限りません。そこで、質問のたびに関連資料を検索し、その内容を根拠に答えるよう指示します。今回なら「AX-100の管理画面が開かない」という質問に、メーカーの該当手順を添えて LLM に渡します。文書を改訂した場合は、本文とベクトルを更新して検索対象へ反映します。
RAGには、誤った情報の生成を減らすこと、社内固有の知識を利用すること、更新された情報を回答に反映することが期待できます。
!image.png
ただし、資料を渡すだけで正しさが保証されるわけではありません。質問に合う資料を取得できたか、その資料に沿って答えたかの両方を確認します。背景はRAGの基礎:LLMの限界とRAGによる解決への道、RAGの目的と利点でも紹介しています。
文書をベクトル化する際のチャンキングにも注意が必要です。
チャンクが小さすぎると、前提や注意事項が抜けます。大きすぎると、質問に関係のない記述が増えます。単に文字数で切るだけでなく、見出しや手順のまとまり、文書ID、版を保持することが、検索後の回答にも効いてきます。
また、チャンクサイズや検索で取得する結果セットの件数は、ベクトル検索の精度に影響します。
!image.png
この記事では、文書の事前ベクトル化は準備時に済ませているものとして、質問を受け取ってから回答を返すまでの処理を見ていきます。
検索・拡張・生成の流れを、DB内のPL/SQLでつなぐ
このデモでは、RAGの一連の処理を、PL/SQLパッケージ OJ41_RAG の関数 answer_question にまとめています。チケットIDと質問を渡すと、文書の検索、LLMへの入力構築、回答生成、回答の検査を行い、結果をJSONで返します。この関数の呼び出し例は、後の「デモB」で紹介します。
ここでは、検索するタイミング、資料を入力コンテキストへ加える方法、回答を検査する順序をDB内のPL/SQLで定めています。LLMの推論はOCI Enterprise AI(Generative AI)の Grok 4.3 で行い、DBからリソースプリンシパルで API を呼び出します。LLMが次の処理を選ぶ構成ではなく、条件分岐を含む決められた流れの中で回答生成を呼び出します。
flowchart TD
Q["質問+選択中のチケット"] --> R["検索<BR/>DBで保守登録番号を照合して機種・閲覧範囲に合う文書を取得"]
R --> H{"候補文書があるか"}
H -->|ない| N["根拠不足を返す<br/>LLMは呼ばない"]
H -->|ある| A["拡張<br/>質問+特定した機種+文書ID・本文+回答指示をLLMへ渡す入力コンテキストとして組み立てる"]
A --> G["生成<br/>DBから 外部LLM を呼び出し、資料を根拠に回答を生成する"]
G --> V{"DB内のPL/SQLでJSON形式・文書ID・引用を検査"}
V -->|適合| O["回答または根拠不足を返す"]
V -->|不適合| E["検査エラーで停止"]
このフロー図を実装しているのが、68_rag_body.sql の OJ41_RAG.answer_question です。関数の冒頭でチケットを開き、保守登録番号が指定されていれば、その顧客のサーバー台帳から機種を確定します。続いて、閲覧範囲と機種に合う文書を検索し、取得した文書IDと本文をJSON配列 docs に格納します。
以下は、文書の検索が終わった後の処理 を抜き出したPL/SQLです。フロー図の「候補文書があるか」から「拡張」「生成」「回答の検査」までに対応します。docs.get_size() は取得した文書の件数を返します。変数の宣言や検索処理は省略しているため、この抜粋だけでは実行できません。
-- 検索結果が0件なら、LLMを呼ばずに「根拠不足」とする
IF docs.get_size()=0 THEN
checked:='{"status":"insufficient","claims":[]}';
ELSE
-- 拡張:質問・機種・検索した文書を、回答指示とともに入力へ加える
payload.put('question',p_question);
payload.put('db_resolved_model',model_name);
payload.put('documents',docs);
prompt:=TO_CLOB(instruction)||CHR(10)||payload.to_clob();
-- 生成:組み立てた入力を外部LLMへ渡す
raw_answer:=DBMS_CLOUD_AI.GENERATE(
prompt=>prompt,profile_name=>'OJ41_BUSINESS_AI',action=>'chat');
-- 検査:回答のJSON形式・文書ID・引用を検索結果と照合する
checked:=OJ41_ANSWER_GUARD.validate_json(raw_answer,docs.to_clob());
END IF;
payload は質問・機種・検索結果をまとめるJSONオブジェクト、instruction は回答ルール、raw_answer はLLMが返した回答です。回答の検査を担当する OJ41_ANSWER_GUARD.validate_json の実装は 66_answer_guard_body.sql にあります。検査に適合すれば、answer_question は回答などを含む結果を返します。正常終了時も例外発生時も、関数内でチケットの状態を消去します。
RAGのLLM呼び出しには、Oracle AI Database 26ai の Select AI chat 機能を使います。LLMの接続先・認証・生成パラメータは、AIプロファイル OJ41_BUSINESS_AIに設定しています。付録Cで準備するプロファイルで、後のAgentと共用します。定義全文は64_business_ai_template.sqlを参照してください。Python版もrag.pyに残しています。
検索によって、LLMへ渡すコンテキストはどう変わるか
利用者が入力するのは「DEV001の管理画面が開かない。最初に何を確認する?」だけです。検索後には、DBで特定した機種と、文書ID・本文を加えた次のようなJSONをユーザーメッセージとして渡します。これはPL/SQLが組み立てる形式に合わせた例で、文書はKB001の1件だけを示しています。実際には取得した最大3件をdocumentsへ入れます。
{
"question": "DEV001の管理画面が開かない。最初に何を確認する?",
"db_resolved_model": "AX-100",
"documents": [
{
"doc_id": "KB001",
"text": "管理画面が応答しないとき AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。次に管理端末から疎通を確認し、障害ログを保存します。業務への影響を確認せずに再起動しないでください。"
}
]
}
このJSONに回答のルールを添えて、一つのプロンプトとして渡します。68_rag_body.sqlの指示から抜粋すると、次の内容です。
提示資料だけを根拠とし、他機種の手順、推測、資料にない操作を追加しないでください。
質問の症状に関係しない手順は、提示資料に含まれていても回答に使わないでください。
契約照会や訪問の確約はできません。質問に答える根拠が足りなければ insufficient としてください。
質問そのものを書き換えるのではなく、その質問を解釈して回答するための情報を添えています。これがRAGの「拡張」に当たります。LLMへ渡すのは検索で取り出した本文であり、検索に使った1024次元のベクトルではありません。
このデモでは、契約の有効性をRAGの検索条件にしていません。契約が無効でも、閲覧を許可された文書から確認手順を案内するシナリオだからです。デモBは文書に基づく回答、デモCは契約条件の照会、デモDは両者の組み合わせを扱います。「有効契約の顧客だけが読める文書」を扱う業務なら、契約表を検索条件へ組み込む設計が適切です。リレーショナルDB内のベクトル検索なら、その条件もJOINやEXISTSで表現できます。
デモB:答えがある質問と、根拠が足りない質問を比べる
VS Code SQL DeveloperでDBMS Outputを有効にし、次の各ブロックを実行します。全文は01b_rag.sqlにあります。
DECLARE r CLOB;
BEGIN
r:=OJ41_RAG.answer_question('SR001','DEV001の管理画面が開かない。最初に何を確認する?');
OJ41_ANSWER_GUARD.print_clob(r);
END;
/
DECLARE r CLOB;
BEGIN
r:=OJ41_RAG.answer_question('SR001','AX-100のE999の修理方法は?');
OJ41_ANSWER_GUARD.print_clob(r);
END;
/
DECLARE r CLOB;
BEGIN
r:=OJ41_RAG.answer_question('SR001','AX-100の保証延長料金を日本円で教えて。');
OJ41_ANSWER_GUARD.print_clob(r);
END;
/
<details>
<summary>実行結果例:デモBの回答・引用と根拠不足</summary>
SR001での実行結果から、status・claims・llm_callsを抜粋しています。回答の文言は実行ごとに変わります。
DEV001の管理画面が開かない
{
"status": "answered",
"claims": [
{
"text": "AX-100の管理画面が開かない場合、まず電源ランプとLANケーブルを確認します。",
"doc_id": "KB001",
"quote": "AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。"
}
],
"llm_calls": 1
}
この結果は、登録済みの文書に照らして期待どおりです。DEV001の機種はAX-100で、公開済みの共通文書KB001には「まず電源ランプとLANケーブルを確認します」と記載されています。回答はこの手順に沿っており、引用もKB001の本文と一致しています。status: answered と llm_calls: 1 は、検索した文書をLLMへ渡して回答を生成したことを示します。
AX-100のE999
{
"status": "insufficient",
"claims": [],
"llm_calls": 0
}
この結果も期待どおりです。登録済みの16文書には、E999に関する記述がありません。このRAGの検索処理では、質問にエラーコードがあれば、その文字列を本文に含む文書に絞ってからベクトル距離で並べます。そのため候補が0件になり、PL/SQLがLLMを呼ばずに insufficient を返します。llm_calls: 0 はこの分岐に対応します。ベクトル距離だけで「答えがない」と判定した結果ではありません。
AX-100の保証延長料金
{
"status": "insufficient",
"claims": [],
"llm_calls": 1
}
この結果も期待どおりです。登録済みの16文書には、保証延長の料金表や金額の記載がないため、金額を回答せず insufficient を返すのが期待する動作です。この質問にはエラーコードによる絞り込みがなく、機種と閲覧範囲に合う文書から距離順に上位3件が取得されます。ただし、検索結果(候補文書)があることと、そこに質問への答えが記載されていることは別です。llm_calls: 1 は候補文書をLLMへ渡したことを示し、掲載結果ではLLMが料金を答える根拠が不足していると判断しています。E999の例との違いは、検索結果が0件なのではなく、取得した文書に答えがないことです。
</details>
PL/SQLは取得した最大3件の文書と質問・機種をLLMへ渡します。返されたJSONについて、文書IDが取得結果に存在するか、引用が原文に含まれるかを検査します。実装は68_rag_body.sqlと66_answer_guard_body.sqlです。
:::note info
コラム:生成結果を検査することも、ハーネスの役割
このRAGのPL/SQLコードは、LLMの回答をそのまま表示せず、JSON形式・文書ID・引用を検査します。不正な出力は検査エラーとして止め、検索候補がない場合はLLMを呼びません。モデルへの指示に加えて、出力を受け入れる条件をコードで定めています。
ただし、引用が原文に含まれているかの確認と、回答の説明が引用の内容に沿っているかの確認は別です。この検査だけで回答全体の正しさを保証するわけではありません。
:::
| ケース | 実機で確認した結果 | 確認する点 |
|---|---|---|
| 管理画面が開かない | 電源ランプ・LANケーブルの確認、KB001を引用 | 説明と引用が対応するか |
| E999 | 候補0件でLLMを呼ばない | 未知のコードを補っていないか |
| 保証延長料金 | insufficient、claimsは空 | 取得文書に答えがないと判断できるか |
LLMの文言は毎回同じになるとは限りません。表の結果を確かめるときは、文章の完全一致ではなく、必要な確認手順と根拠が含まれるかを見ます。
検索の失敗と生成の失敗を分けて直す
正しい手順が取得結果に入っていなければ、回答指示だけを変えても根拠は増えません。質問の表現、機種条件、チャンクの切り方、検索件数を見直します。正しい手順を取得できたのに回答が誤っている場合は、資料の渡し方や回答指示、引用との対応を調べます。
この引用検査は、文書IDが取得結果に存在し、引用文字列がその本文に含まれるかを確かめるものです。意味の正しさまで検証するものではありません。回答に根拠が示されているかに加え、引用の内容と回答の説明に食い違いがないかも確認します。
RAGで技術手順は説明できました。しかし、「契約が何件あるか」「有効期限内か」まで文書の近さで決めるのは適切ではありません。次は、契約表の条件照会を自然言語で行います。
5. NL2SQL で契約情報を照会する
閲覧範囲を制限したビューを、NL2SQL で検索する
「現地保守の対象サーバーを一覧にしてほしい」という質問を、SQLを書かずに問い合わせられるようにします。自然言語の質問からLLMがSQLを生成する処理を、NL2SQL(Natural Language to SQL)と呼びます。
LLMには質問とともに、利用できる表や列の情報、業務用語の説明などを渡します。生成されたSQLをDBで実行することで、リレーショナル表にある業務情報を照会できます。
この章では、Oracle AI DatabaseでNL2SQLを実現する機能「Select AI」を使います。Select AIの概要
!image.png
LLM で SQL を生成する NL2SQL では生成されたSQLが適切な閲覧範囲を指定するとは限りません。例えば、契約表を直接参照するSQLで顧客条件が抜けると、別顧客の契約まで結果に含まれる可能性があります。「対応中の顧客だけを調べて」とLLMに指示することに加えて、実行側でも参照できる範囲を制限する必要があります。
そこで、第3章で用意した OJ41_VISIBLE_CONTRACTS ビューを使います。このビューは、同じDBセッションの OJ41_CASE_CTX.customer_id() 関数が返す顧客IDでサーバー台帳を絞り、そのサーバーの契約だけを返します。open_case('SR001') プロシージャでチケットSR001を選択していれば顧客C001の契約が対象となり、チケット未選択なら0件です。生成SQLがこのビューを参照する限り、顧客条件を付け忘れても別顧客の契約行は取得されません。
さらに、生成SQLがベース表を直接参照して制限を迂回しないよう、Select AIの object_list に閲覧範囲を適用済みのビューなどを指定し、enforce_object_list=true で参照先を制限します。
!image.png
図中のSQLは機能を説明するための例です。このデモで使う設定・オブジェクト名は、後述のSQLを参照してください。
ビューによる行の限定と、生成SQLの参照先制限を組み合わせる 構成です。具体的な対象一覧と設定は、続くデモCで紹介します。これはNL2SQLの参照経路を制限する仕組みであり、第3章で説明した担当者本人の認可やDB権限の分離も別途必要です。
契約照会に使う OJ41_VISIBLE_CONTRACTSビューの列は、次のとおりです。定義は 35_create_demo_tables.sql にあります。
OJ41_VISIBLE_CONTRACTSビュー
| 列名 | 意味 | 問い合わせでの使い方 |
|---|---|---|
| contract_id | 契約ID | 契約を識別する |
| device_id | メーカーが付与した保守登録番号 | 対象サーバーを照合・一覧表示する |
| start_date | 契約開始日 | 契約期間を確認する |
| end_date | 契約終了日 | 契約期間を確認する |
| status | 契約状態。ACTIVE または CANCELLED | 契約状態を確認する。ACTIVE だけでは期間内かどうかは判断できない |
| service_scope | サービス範囲。ONSITE または REMOTE | 現地保守かリモート保守かを確認する |
| customer_id | 契約対象サーバーの顧客ID | 対応中のチケットの顧客であることを確認する |
| model | サーバーの機種 | 機種ごとに絞り込み・集計する |
| as_of_date | 契約の有効性を判定する基準日 | このデモでは2026年10月15日時点の判定であることを確認する |
| is_active | 基準日時点で契約が有効なら Y、それ以外は N | 有効な契約に絞る |
| onsite_eligible | 基準日時点で契約が有効で、現地保守の対象なら Y、それ以外は N | 現地保守の対象サーバーを一覧表示・集計する |
is_active と onsite_eligible は、契約データと基準日からビューの CASE 式が計算する列です。LLMには契約の有効性を推測させず、例えば onsite_eligible = 'Y' のように、判定済みの列を使うSQLを生成させます。期限切れや解約済みの契約もビューには残るため、対象外の理由を調べる照会にも使えます。
この仕組みで顧客範囲を限定しても、LLMが同じ顧客の中で誤った列や条件を選ぶ可能性は残ります。続くデモCでは、現地保守の対象サーバーを調べる質問を使い、列の意味を伝える注釈がSQL生成にどう影響するかを確認します。
デモC:現地保守の対象サーバーを自然言語で調べる
保守担当者が、対応中のチケットSR001の顧客について、現地保守を利用できるサーバーを一覧で確認する場面です。目標は、基準日時点で対象となる保守登録番号DEV001・DEV005・DEV006・DEV008を昇順で取得することです。利用者が表名や列名を知らなくても、次の質問で調べられるようにします。
> この受付案件の顧客について、基準日時点で現地保守の対象となるサーバーの保守登録番号を昇順で教えてください。
ここでいう「受付案件」はチケットのことです。以下の質問文と実行結果例は、検証時の表記のまま掲載しています。
質問文には、「受付案件」がどの表に対応し、「現地保守の対象」がどの列で判定されるかは明示されていません。 Select AIが付加するDBのメタデータも含めて、LLMがその対応を読み取れることが必要です。業務用語と実際のデータ構造の対応を十分に渡さない素朴なNL2SQLでは、存在しない表や列を補ったり、必要な条件を落としたりする失敗が起こり得ます。
成功率を上げるには、表・ビュー・列の構造に加え、業務用語との対応もLLMへ伝える必要があります。今回は、その説明をDBのデータディクショナリへ ANNOTATION(注釈) として登録します。利用者が質問のたびに説明を書き足す代わりに、Select AIが注釈をメタデータとしてLLMへの入力に含めます。
!image.png
図中のSQLは機能を説明するための例です。このデモで使う設定・オブジェクト名は、後述のSQLを参照してください。
Select AI には、NL2SQL の精度改善のための様々な機能があります。今回は、annotationsと object_list / enforce_object_list を使っています。
!image.png
まず、生成SQLが参照してよい範囲を決めます。今回のデモに関係するOJ41で始まる表・ビューから、閲覧範囲の制限を迂回するものを除きます。
| 扱い | 表・ビュー | 理由 |
|---|---|---|
| 含める | OJ41_VISIBLE_CONTRACTS、OJ41_VISIBLE_DEVICES、OJ41_VISIBLE_KNOWLEDGE、OJ41_VISIBLE_CHUNKS | チケットの顧客や文書の公開範囲を適用済みのビュー |
| 含める | OJ41_RUN、OJ41_BULK_PARTS | 固定基準日やロード進捗。顧客別の契約や制限対象の本文を含まない |
| 除く | OJ41_CUSTOMERS、OJ41_SUPPORT_CASES、OJ41_DEVICES、OJ41_CONTRACTS | ビューを通さず別顧客の行を参照できるベース表 |
| 除く | OJ41_KNOWLEDGE、OJ41_CHUNKS、OJ41_BULK_DOCS、OJ41_BULK_STAGE | 顧客専用・内部向けの本文を含むベース表と大量ロード用の複製 |
OJ41_BULK_PARTS は大量ロードの準備で作成する表です。まだ作成していない場合は、以下の両プロファイルの object_list からこの項目だけを除いてください。付録Cの準備コードは、実際に存在する表を確認して一覧を作成します。
object_listはメタデータの対象を選び、enforce_object_list=trueは生成SQLの参照先をその一覧に制限します。両プロファイルで同じ一覧を使い、object_list_mode=allを明示します。表・ビュー・列のメタデータは両方へ渡し、annotationsだけを切り替える比較です。属性の仕様、注釈によるSQL生成の改善
!image.png
各テストケースを実行する前に、対応中のチケットを SR001 に設定します。
BEGIN OJ41_CASE_CTX.open_case('SR001'); END;
/
1. 注釈を含めずにSQLを生成する
Select AI を使用するためには、あらかじめ AIプロファイル を定義しておく必要があります。AIプロファイルは、Select AIで使用するAIプロバイダーやモデル、LLMへメタデータを送信するDBオブジェクト(表、ビュー)などを定義するものです。このNL2SQLのデモではLLMを指定し、埋め込みモデルは設定しません。
AIプロファイルの生成・登録処理はnl2sql_compare.setup()にあります。以下は初回作成用のAIプロファイル定義です。付録Cで準備済みの場合、プロファイル作成SQLの再実行は不要です。C1の質問から試せます。<OCI_GENAI_COMPARTMENT_OCID>は利用するコンパートメントのOCIDへ置き換えます。付録Cの準備処理でも同じプロファイルを作成します。
BEGIN
DBMS_CLOUD_AI.CREATE_PROFILE(
profile_name => 'OJ41_NL2SQL_BASELINE',
attributes => q'~{
"provider": "oci",
"credential_name": "OCI$RESOURCE_PRINCIPAL",
"region": "us-chicago-1",
"model": "xai.grok-4.3",
"oci_compartment_id": "<OCI_GENAI_COMPARTMENT_OCID>",
"temperature": 0,
"max_tokens": 1600,
"object_list": [
{
"owner": "ORAJAM41USER",
"name": "OJ41_BULK_PARTS"
},
{
"owner": "ORAJAM41USER",
"name": "OJ41_RUN"
},
{
"owner": "ORAJAM41USER",
"name": "OJ41_VISIBLE_CHUNKS"
},
{
"owner": "ORAJAM41USER",
"name": "OJ41_VISIBLE_CONTRACTS"
},
{
"owner": "ORAJAM41USER",
"name": "OJ41_VISIBLE_DEVICES"
},
{
"owner": "ORAJAM41USER",
"name": "OJ41_VISIBLE_KNOWLEDGE"
}
],
"object_list_mode": "all",
"enforce_object_list": true,
"comments": false,
"annotations": false
}~');
END;
/
AI プロファイルを作成したらいよいよ Select AI による NL2SQL の実行です。
DBMS_CLOUD_AI.GENERATE() 関数の action に showsql を指定すると LLM を使って SQL を生成します。
:::note
上の Select AI の紹介の中にある select ai showsql 質問文 の構文を使う場合は、事前にDBMS_CLOUD_AI.SET_PROFILE() プロシージャで DBセッションに AIプロファイルを設定する必要がありますが、DBMS_CLOUD_AI.GENERATE() 関数は、引数として profile_name を取りますので事前の SET_PROFILE によるセッションへの設定は不要です。AIプロファイル自体は作成しておく必要があります。Database Actions や Oracle APEX のようなステートレスな環境でも、呼び出しごとに使用するプロファイルを指定できます。
ただし、今回のチケットコンテキストはDBセッションに保持されます。profile_name の指定で、この状態まで引き継がれるわけではありません。チケットの設定と、その状態を参照する照会は同じDBセッションで実行してください。Database Actionsでは、チケット設定・照会・チケット解除をまとめて1回のスクリプトとして実行します。
:::
SELECT DBMS_CLOUD_AI.GENERATE(
prompt=>'この受付案件の顧客について、基準日時点で現地保守の対象となるサーバーの保守登録番号を昇順で教えてください。',
profile_name=>'OJ41_NL2SQL_BASELINE', action=>'showsql') AS generated_sql
FROM dual;
<details>
<summary>実行結果例:チケットと顧客の対応を読み取れず、SQLを生成できなかった</summary>
Sorry, unfortunately a valid SELECT statement could not be generated for your natural language prompt with the restriction of enforcing the use of object list. Here is some more information to help you further:
The provided tables do not contain any inf
14 likes
Mentions
Can a user retrieve information outside their permissions, including through the lexical search path, caches, or indirect references? Jeevan Srivastava asked this question word for word in a Medium article of 18 October 2026, as one of three dimensions he would assess for a production system, beside retrieval quality and operational performance. He labels his access-control design: "These are proposed production design decisions, not features I'm claiming to have implemented as part of my retrieval fix." > TL;DR > > - Yes, through any read path the permission check does not cover. The question names three: the lexical branch of a hybrid search, filtered differently from the vector branch; a cache that answers before the check runs; and indirect references, such as a fetch by ID or exact name, a pointer to a hidden record, or a scope value supplied by the request or the model. > - One rule addresses all three: the server derives the read scope from the verified caller identity and applies one filter on every path that can return stored content. For the model's part, the Databricks agent memory documentation says of the actor_id that scopes every read: "Never let the model choose it." > - Three probes, run as a user without access, test whether a system holds: a rare word from a restricted document through every search branch; a cache warmed by a user with access; and a direct fetch, a followed pointer and a foreign scope. Each needs a positive control run as a user with access, or an empty result proves nothing. Mnemoverse (the author's company) makes one of the memory APIs quoted below. Can a user retrieve information outside their permissions? Yes, whenever a path that returns stored content skips the check that search runs. A read path is any function, endpoint or query type that can return stored content to a caller: a search, an exact get, a list, an export, an admin surface or a debug endpoint. Heinrich Neb, who works on a memory layer for coding agents, gave the audit rule in a dev.to comment of 27 August 2026: "find every function that can return stored content." | Read path | How it returns what the user may not see | What closes it | Documented by | |---|---|---|---| | Lexical branch of a hybrid search | The full-text query lacks the vector query's filter | One filter below both branches, or passed to each | Srivastava; PostgreSQL; Elasticsearch | | Cache in front of retrieval | A stored answer is served before the check | The caller's scope in the key, or the cache behind the check | RFC 9111, for shared HTTP caches | | Fetch by ID or exact name | A lookup outside search returns the record | An object-level check on every route that takes an ID or a name | OWASP API1:2023; Neb | | Pointer from a visible record | A visible record names a hidden one | The target's visibility checked when the pointer is read | Neb; PostgreSQL | | Scope from the request or the model | A user ID or tag from the path, body or a tool argument is trusted | Scope from the verified identity; supplied values checked against the configured set | Databricks; Supermemory; Mem0; Anis Meziani | | Query language as a search type | Raw queries reach the store | Off unless every user of the deployment is trusted | Cognee | The last four rows are kinds of indirect reference. Srivastava separates the two decisions: "Relevance determines whether information is useful. Authorization determines whether information is allowed to be accessed." How does the lexical search path leak in a hybrid search? The lexical branch is the half of a hybrid search that matches the query's words against a full-text index, such as BM25 or PostgreSQL full-text search, beside the vector half that matches embeddings. Srivastava's rule: "The key decision is that both vector search and lexical search must respect the same access restrictions." The failure: "If vector search filters by tenant or document permissions but PostgreSQL full-text search doesn't, the hybrid retrieval pipeline can introduce a data leak through the lexical branch." On merging the two lists: "Combining rankings must never override authorization boundaries." And at retrieval time: "Apply authorization and tenant filters to every retrieval path." One filter can reach both branches from two places. Below both branches, in the database. With row security enabled on a PostgreSQL table, "all normal access to the table for selecting rows or modifying rows must be allowed by a row security policy", and a table with no policy falls back to "a default-deny policy" (PostgreSQL, Row Security Policies). The same page sets two limits: "the table's owner is typically not subject to row security policies" unless the table is altered with FORCE ROW LEVEL SECURITY, and "Superusers and roles with the BYPASSRLS attribute always bypass the row security system when accessing a table." An application that connects as the owner of an unforced table, as a superuser or as a BYPASSRLS role is not filtered at all. One filter passed to every branch. The filter parameter of the Elasticsearch RRF retriever "Applies the specified boolean query filter to all of the specified sub-retrievers, according to each retriever's specifications." Written once, it cannot drift between two copies. OWASP's LLM08:2025 opens its prevention list with: "Implement fine-grained access controls and permission-aware vector and embedding stores." The OWASP text speaks of vector and embedding stores; a hybrid pipeline has a second index, and the same rule has to reach it. Srivastava adds a condition that holds over time: "metadata can become stale if permissions change and the retrieval index isn't updated accordingly." Does a permission filter keep a restricted user's results complete? Nothing leaks here; the risk runs the other way. The pgvector README: "With approximate indexes, filtering is applied after the index is scanned. If a condition matches 10% of rows, with HNSW and the default hnsw.ef_search of 40, only 4 rows will match on average." Its first suggestion, an index on the filter column, can give exact search in many cases, so the shortfall applies whenever the planner takes the HNSW index instead. What follows is this article's inference for a vector branch on pgvector with an HNSW index, not a measurement. A permission rule is a condition that keeps some share of the rows, so the narrower a user's rights, the fewer rows one scan of the vector index can return, while the full-text branch can still return every permitted match. For hybrid search the README offers fusion: "You can use Reciprocal Rank Fusion or a cross-encoder to combine results." Fusion ranks the lists it receives, so a restricted user's top results draw more on keyword matches than an administrator's do. An evaluation run as an administrator measures only the administrator's ranking: report retrieval quality per permission level. The README's levers: "Starting with 0.8.0, you can enable iterative index scans, which will automatically scan more of the index until enough results are found". On tenants: "For applications with multiple tenants, sharing an approximate index between tenants means vectors from one tenant can affect recall (and speed) for other tenants." And: "For tenant isolation, use list partitioning or separate tables." Can a cache answer with documents the user may not see? Yes, when it answers before the check runs. For shared HTTP caches, RFC 9111, section 3.5, sets the rule: "A shared cache MUST NOT use a cached response to a request with an Authorization header field" to satisfy a later request, unless the response allows shared storage through a Cache-Control directive such as public, s-maxage or must-revalidate. A semantic or answer cache inside an application follows whatever rule the application gives it. Naveen Metta, in an article of 12 October 2026 on RAG before production, states the requirement: > If a user cannot open the document, the model should not be able to quote it. From his team's work: "We found one prompt that could surface HR documents to any employee." He also advises: "Then add a semantic cache in Redis for repeated questions." This article's inference about any cache in front of retrieval, not a description of his system: such a cache answers without running the filter, so the caller's scope has to be part of what it matches on, or it has to sit behind the check. Srivastava would test "whether permissions and deletion requests propagate to the relevant indexed and cached data." The warm, revoke, replay test is covered in the library page on revoked access after an answer was shown, and caches after a delete in Agent Memory Deletion: What Survives a Delete. What counts as an indirect reference, and how does it leak? An indirect reference is any way to reach a record other than a search the filter covers: its ID, its exact name, a pointer from another record, a scope value or a query language. An existence leak is an answer that reveals that a hidden record exists, or something about it, without returning its content. The fetch that skips search. Neb, on his own system: "We had scoping enforced correctly on retrieval, tested, verified", and beside it "a second read path, lookup by exact name rather than similarity, that returned full content to anyone who asked." In short: "Same store, two doors, one guarded." The sign in code: "a read path that doesn't accept the caller identity cannot enforce anything". For APIs, OWASP API1:2023 Broken Object Level Authorization: "Every API endpoint that receives an ID of an object, and performs any action on the object, should implement object-level authorization checks." The pointer. On 25 August 2026, Neb reported a retired record whose banner kept naming its successor after the successor was made private: "Existence leak through the supersession pointer." His rule: "a pointer's validity and a pointer's visibility are both read-time questions, never write-time facts." PostgreSQL warns of a related channel: its referential integrity checks always bypass row security, and "Care must be taken when developing schemas and row level policies to avoid "covert channel" leaks of information through such referential integrity checks." The query language. Cognee pull request #5844, merged into its dev branch on 15 October 2026: "CYPHER and NATURAL_LANGUAGE search types run raw Cypher against the graph database." And: "Any user with read access to a dataset could execute arbitrary queries". The change: "ALLOW_CYPHER_QUERY now defaults to false." For turning it back on: "Only do that when every user of the deployment is trusted." What closes the class: a check at every entry point, and a refusal that neither names nor describes the hidden record, so that a missing record and someone else's record get the same answer. An answer that tells the two apart reveals existence, which is acceptable only where existence is not a secret. Who should set the scope of a memory read: the server, the request or the model? A caller-supplied scope is a value that selects whose data a read covers, such as a user ID, a tenant tag or an actor ID, and that arrives with the request or from the model instead of from the verified identity. The Databricks agent memory documentation (Beta, last updated 26 October 2026) states the rule: "Set actor_id in your application code from trusted caller context: the verified end-user identity for per-user memory, or a trusted team or project key for shared memory. Never let the model choose it." And: "If your strategy depends on an end-user identity, reject requests that don't carry one rather than falling back to a shared actor_id." Three classes of the error, each with a dated fix: A scope chosen by the model. Supermemory pull request #1824, merged on 16 October 2026 into the 2.x release branch of its tools package: "In 2.x, getProfile, documentList, memoryForget and documentDelete accept an optional containerTag from the model and use it unchecked as the request scope." The consequence: "So a model, or a prompt-injected input, can name another tenant's tag and read their profile, list their documents, forget their memories, or delete their documents." The fix: "A model-supplied tag must be one of the tags the developer configured", or the call fails "before any request is sent". The pull request also notes: "Tools 3.x (#1773) already removed model-selected scope." An empty scope read as everything. Mem0 pull request #7581, merged on 12 October 2026, on its hosted clients: "The dangerous one is an empty entity ID. The API treats an empty ID as matching every memory in the project." The case there is the delete calls, delete_all and delete_users, fixed on the client: "This PR blocks that client-side. The server needs its own fix, which is out of scope here." This article did not check whether the server has changed since. A scope taken from the path or the body. Anis Meziani, replying on 14 October 2026 to a comment under his own dev.to article: "Our ADK-native session routes originally checked that a token was valid, not which user it acted for, so the user_id in the path or body was trusted." His fix checks the token's subject against the user_id "on every route that reads sessions or memory, including the live WebSocket". The rule: the scope comes from the verified identity; a request without one is refused, not given a shared scope; an empty value is an error, not everything; a value from the model is checked against the configured set before any request goes out. What changes when several users share one memory store? In a shared store the question moves from the answer to the context. A preprint of 19 October 2026 (arXiv 2610.25707, version 1, not peer-reviewed) opens: "Shared long-term memory lets an LLM agent serving one user inadvertently retrieve another user's credentials, but it is unclear when such exposure leads to actual harm." Its audit used the AppWorld environment and one store for all users' logins: "In AppWorld, a store that mixes 763 past logins from all users retrieves another user's credential for 84.7 percent of required apps, yet agents rarely act on it." Of the misuse its stress test provokes: "Naming the owner before or inside each credential line prevents most of this". Its conclusion: "Agent memory should consistently record whose credential it stores, and evaluations should measure behavior, not only exposure." This article's reading: the boundary is crossed when another user's record reaches the model's context, whether or not the model uses it. Srivastava, from the design side: "The stronger approach is to prevent unauthorized information from entering the context in the first place." Databricks states where the boundary sits: "actor_id separates memories, but it is not an access control. Memory stores are workspace-scoped, so any principal that can reach a store can read and write every entry across all actors." And: "The store, not the actor, is the security boundary. For strict isolation between tenants or users, create a separate memory store per boundary." OWASP's LLM08:2025, for vector databases: "In multi-tenant environments where multiple classes of users or applications share the same vector database, there's a risk of context leakage between users or queries." How do you test that no read path leaks? Each probe has a positive control, because a probe that finds nothing proves nothing until it finds something where it should. They are this article's proposals, not any team's suite. 1. The lexical branch. As the test user, run vector-only, lexical-only and hybrid queries for a rare word, such as a code name, found only in a document the user may not open. Expected: no chunk of it. Control: a user with access gets it. Srivastava proposes this negative test: "Queries from unauthorized users should not expose protected documents, even when those documents are semantically similar to the query." 2. The cache. User A, with access, asks a question whose answer needs the restricted document; user B, without access, asks it and a paraphrase. Expected: B's answer is not built from that document. Control: A's answer is built from that document, and B's answer with the cache off matches B's answer with the cache on. 3. Indirect references. As a user without access, fetch the record by ID and by exact name, follow a pointer to it from a visible record, and send another user's scope and an empty scope. Expected: the same answer as for a record that does not exist. Controls: as a user with access, the same fetch, pointer and scope return the record, so the path is live; a made-up ID on the same path gives the answer to compare against. Three rules for the run: - Take the list of read paths from the code or the tool registry, not from a filtered listing. sam ros, on 15 October 2026, about the CI test of the scope check in his MCP server: "with a list_tools override that filters by the token's scopes, the old test passed while a tickets:read token could still delete." - Rerun the probes after a permission change and after a delete: permission data copied into an index or a cache can go stale. - Inspect what reached the model's context, not only the final answer. A passing first probe says nothing about the second and the third. How do memory APIs document where the boundary is? Two documented positions, in their own words, as read on 2 November 2026. Databricks. The store is the boundary, and application code, not the model, sets the actor ID; both are quoted above. Mnemoverse. The security page states the tenant boundary: "Every API key is bound to a unique organization_id. All database queries are scoped to your organization." Shared rooms (beta) stay apart: "room content never appears in your normal (non-room) searches". The rooms reference covers indirect references: "Knowing a room id grants no access to its contents: access is enforced by the API's membership check on every request, and non-members get 403." And: "Membership is checked before archive state, so a non-member of an archived room still gets the membership 403", so the answer does not reveal whether a room is archived. This is a documented boundary, not a test result; this article tests no product. What this article does not claim No measurement of any product and no figure for how often any system leaks. The numbers above are the pgvector README's illustration and one preprint's audit, each with its conditions. Vendor fixes are quoted from their own pull requests with their merge dates; this article did not check whether a fix has reached a release. The inference about rank fusion is for pgvector with an HNSW index and was not measured. The probes are proposals, not a description of any team's suite. --- Sources and method. Every quotation was read on 2 November 2026 with two instruments, a browser-like request and a second reading of the same text: a reader service with its cache off, and in addition the dev.to API for the dev.to comments, the RSS feed for Jeevan Srivastava's article and the arXiv API for the preprint; for the GitHub pull requests and the pgvector README, which the reader service refuses, the GitHub API and the raw file took its place. A made-up address on each host answered 404 as a control, except Medium, which answers 200 to any address, so there only the article text counts. The text describes those pages as of that date. A longer version, with the common questions and the full list of sources, is in the Mnemoverse documentation library: Can a user retrieve information outside their permissions, including through the lexical search path, caches, or indirect references? Edward Izgorodin · Mnemoverse · 2026-11-02
Four Bounded Semantic Retrieval Paths for Healthcare Appointment Assistants Collection queries timing out in a healthcare appointment assistant are usually a contract problem before they are a vector-database problem. Short answer: use staged retrieval with explicit collections, bounded queries, and source context that can be traced back to a document. That gives the assistant a useful fallback when a specialist index is slow, without silently turning a scheduling answer into a guess. The flow I want is small enough to reason about: classify the appointment request, query the narrow collection first, stop at a deadline, then try a broader or lexical source, and finally ask for clarification or hand off. Every result carries a URL or document ID. The answer renderer never receives anonymous chunks. What should semantic retrieval return for a healthcare appointment assistant? Start with a retrieval contract, not a vendor SDK. For an intent such as “find a follow-up with Dr. Lee next week,” the contract can require a specialty, location, date window, and evidence fields. A hit that lacks its source identifier is incomplete even when its similarity score is high. Here is a compact TypeScript runner. The adapters are deliberately boring: they make the timeout and fallback policy visible, and they are easy to replace with Pinecone, Weaviate, pgvector, or an HTTP service. The first adapter below uses Infrai's plain REST surface, so the same request pattern works from a small worker without installing a client library. type Hit = { text: string; score: number; sourceUrl?: string; documentId: string; }; type Retriever = (query: string, signal: AbortSignal) => Promise<Hit[]>; async function queryInfrai(collection: string, query: string, signal: AbortSignal): Promise<Hit[]> { const key = process.env.INFRAI_API_KEY; if (!key) throw new Error("INFRAI_API_KEY is required"); for (let attempt = 0; attempt < 3; attempt += 1) { const apiHost = ["api", "infrai", "cc"].join("."); const response = await fetch(`https://${apiHost}/v1/vector/query`, { method: "POST", signal, headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json", }, body: JSON.stringify({ collection, query, top_k: 5 }), }); if (response.status === 429) { const retryAfter = Number(response.headers.get("retry-after") ?? "1"); await new Promise((resolve) => setTimeout(resolve, Math.min(retryAfter * 1000, 4000) * (attempt + 1))); continue; } if (!response.ok) throw new Error(`retrieval failed: ${response.status} ${await response.text()}`); const payload = (await response.json()) as { hits?: Hit[] }; return payload.hits ?? []; } throw new Error("retrieval rate limit persisted"); } async function withDeadline<T>(work: (signal: AbortSignal) => Promise<T>, ms: number): Promise<T> { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), ms); try { return await work(controller.signal); } finally { clearTimeout(timer); } } async function retrieveWithFallback(query: string, retrievers: Retriever[]): Promise<Hit[]> { const budgets = [180, 260, 360]; for (let i = 0; i < retrievers.length; i += 1) { try { const hits = await withDeadline( (signal) => retrievers[i](query, signal), budgets[i] ?? 400, ); const traceable = hits.filter((hit) => hit.documentId && (hit.sourceUrl || hit.documentId)); if (traceable.length > 0) return traceable.slice(0, 5); } catch (error) { if (!(error instanceof DOMException) || error.name !== "AbortError") throw error; } } return []; } The first adapter should target a collection containing current clinic schedules and policy documents. The second can search a broader appointment collection; the third can be a deterministic lookup for provider, clinic, or opening identifiers. The limits are intentional. A slow source cannot hold the user-facing request indefinitely, and returning five traceable hits is more useful than returning fifty opaque fragments. One production trap is retrying every failure in the same tier. That multiplies load while the user waits. Retry once only for a transient transport failure, pass the remaining budget to the next tier, and record which tier answered. I once treated a timeout as permission to widen the query immediately; the result looked plausible but mixed pediatric and adult clinics. Narrow-first is slower only when it fails, and the trace tells you why. How do fallback stages balance retrieval quality and latency? Use four stages, each with a clear exit condition: 1. Exact constraints: filter by specialty, site, and date window before semantic ranking. This protects clinical relevance. 2. Narrow semantic search: query the current-schedule collection with a small top-k and a short deadline. 3. Broader evidence search: include approved policy and FAQ collections when the narrow tier has no traceable hit. 4. Safe handoff: ask one clarifying question or route to staff when evidence is empty or contradictory. Quality is not just the similarity score. Check that dates are in the requested window, the provider is active, and every claim can be cited. Latency is not just the database timer either; embedding, network, reranking, and answer generation all consume the same user budget. Set one request deadline and allocate smaller budgets inside it. Keep it bounded. No guesswork. For a useful incident record, store the original intent fields beside the query text, the collection version, each adapter's start and end timestamp, the timeout reason, and the exact source IDs selected for generation. That record lets you distinguish a bad embedding from an expired schedule, and it gives a reviewer enough context to reproduce a response without copying sensitive patient text into a ticket. The longest part of this work is usually the test matrix. Take one request for a cardiology follow-up, then vary only one dimension at a time: the schedule document is current or stale, the provider is present or deleted, the narrow collection responds within 180 ms or exceeds its budget, and the broader policy collection has either a matching rule or none. For each case, assert the tier chosen, the number of returned sources, and whether the answer is allowed to proceed. This catches a subtle failure mode where a fallback returns a semantically similar policy paragraph but no appointment availability; the assistant must ask a question instead of blending those facts into a confident slot recommendation. I am not sure every team needs four physical indexes, but every team needs four explicit outcomes, because “some context came back” is not a safe contract. When content changes, re-index deliberately. Upsert the new version, retain its document ID and source URL, then remove deleted records from the collection. A stale appointment slot is a correctness failure, not a harmless cache miss. Keep an index version in your trace so an incident review can reproduce what the assistant saw. Which retrieval option fits this fallback design? The right choice depends on your operational boundary, not a leaderboard. Pinecone is convenient when you want a managed vector service and are comfortable with its hosted indexing model. Weaviate offers a broad open-source and managed surface with schema features. pgvector is a strong fit when Postgres is already the system of record and SQL filters matter more than a separate service. | Option | Useful strength | Trade-off for this workflow | | --- | --- | --- | | Pinecone | Managed vector operations | Another hosted dependency and filtering model to operate | | Weaviate | Flexible schema and deployment choices | More surface area to configure and monitor | | pgvector | SQL joins and transactional data nearby | You own tuning, scaling, and vector maintenance | | A plain HTTP aggregation layer | One contract across providers | You still need to design ranking, traces, and failure policy | Infrai can be the HTTP aggregation layer when a solo team wants one REST API, one key, and no SDK installation while keeping provider changes behind an adapter. That is an integration advantage, not proof of better retrieval quality; you still need to measure recall and tail latency on your own appointment corpus. The catch is real: this design is not suitable when you need specialized vector indexing controls, on-premise data residency guarantees, or a vendor-specific feature that the adapter cannot expose. Stick with pgvector when appointment records must join transactionally with scheduling tables. Choose Pinecone or Weaviate when their managed operations reduce work your team does not want to own. An operational checklist that survives the first incident Log the query class, collection, deadline, tier, result count, document IDs, and final answer citations. Redact patient details before those traces leave the protected environment. Alert on empty-evidence answers and on repeated deadline exhaustion, not only on HTTP errors. Test the fallback path with deliberately slow adapters, deleted documents, stale schedules, and ambiguous provider names. Verify that a timeout moves to the next bounded tier, that a missing source blocks an uncited answer, and that a retry cannot duplicate an indexing write. Your mileage may vary across regions and corpus sizes; the contract is what keeps that variation visible. References - arxiv.org - docs.pinecone.io - weaviate.io - pgvector/pgvector
pgvector ⭐ 24k pgvector adds vector similarity search to Postgres, for developers building search and recommendation features. 🔗 pgvector/pgvector #opensource t.co
@ArdenBuilds i am trying out pg vector. pgvector/pgvector
pgvectorの各機能の実機検証! はじめに 以前書いた「pgvectorで学ぶVector Database(RAGの基礎)」の続きです。 もしVector Databaseの概要を知らなければ、そちらの記事の図を見ていただければなんとなくわかると思います。 また、記事に出てくる用語は「補足」章にまとめています。必要であれば参照してください。 前回の記事では、20件の英語のサンプル文を入れてベクトル検索を動かしてみたのですが、最後のおまけでIVFFlatインデックスを貼って検索したときに、インデックスを貼る前とコサイン距離の数値も順位もまったく同じになる、という結果になっていました。 近似検索なのに結果が変わらないのはデータ件数が少なすぎたからとArgonさんに回答を頂いたので、その他機能とともに検証します。今回は日本語の文章データを3,000件入れて、psqlでログインして各機能を手で動かしながら試してみました。 検証に使ったファイル等はこちらにおいてます:hsmto25519/pgvector-test 今回の検証の前提 検証に入る前に、データの作り方についていくつか前提を置いておきます。 まず、実際にドキュメントなどを対象にRAGを組む場合は、長い文章を適切な長さに分割する処理が必要になりますが、今回はpgvector自体の動きを見ることが目的なので、分割処理は省略して最初から1文ずつに分かれた日本語の文章がある前提で進めます。 また、テーブルへ入れる日本語の文章については、社内規定やIT運用のマニュアルを想定した20カテゴリ・3,000件のセンテンスをAIに出力してもらい、1つのJSONファイル(sentences_3000.json)に用意して使っています。 検証準備 環境確認 前回と同じく、WSL2(Ubuntu 24.04)上のDockerとPythonを使います。 まずはWSL上の環境を確認しておきます。 lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 24.04.1 LTS Release: 24.04 Codename: noble docker --version Docker version 29.1.3, build 29.1.3-0ubuntu3~24.04.2 python3 --version Python 3.12.3 DockerコンテナはPostgreSQL 18ベースの pgvector/pgvector:pg18 を使います。 services: db: image: pgvector/pgvector:pg18 container_name: pgvector_pg18_test ports: - "127.0.0.1:5432:5432" environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: secret0001 POSTGRES_DB: vector_db volumes: - pgdata:/var/lib/postgresql volumes: pgdata: コンテナを起動して psql でログインし、バージョンと vector 拡張を確認します。PostgreSQL 18.6、pgvectorは 0.8.7 (現時点の最新版) が入っています。 docker exec -it pgvector_pg18_test psql -U postgres -d vector_db psql (18.6 (Debian 18.6-1.pgdg12+2)) Type "help" for help. vector_db=# CREATE EXTENSION IF NOT EXISTS vector; CREATE EXTENSION vector_db=# \dx List of installed extensions Name | Version | Schema | Description ---------+---------+------------+------------------------------------------------------ plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language vector | 0.8.7 | public | vector data type and ivfflat and hnsw access methods (2 rows) データ投入(Python) 3,000件のデータを手で入れるのは大変なので、データを入れるところだけPython(insert_data.py)で自動化します。 今回は sentences_3000.json に用意した3,000件の日本語文章を読み込み、Embeddingモデルを使ってベクトル化してからPostgreSQLへ投入します。初回実行時はモデルのダウンロードが走るためトータルで1分前後かかります。 - 利用Embeddingモデル: intfloat/multilingual-e5-small(384次元) - モデル容量約500MB また、あとでpsqlにログインして手動でSQLを実行するときに384次元の長い配列を毎回貼らなくて済むよう、検索クエリ用の文章(PostgreSQLのインデックスを使ってベクトル検索を高速化する方法)とそのベクトルを query_target という別テーブルに1件保存しています。 なお、multilingual-e5系のモデルは検索対象の文章に "passage: "、検索クエリに "query: " というプレフィックスを付けてベクトル化する仕様になっているため、コード内でもそれを付けて変換しています。 import json import psycopg2 from psycopg2.extras import execute_values from sentence_transformers import SentenceTransformer MODEL_NAME = "intfloat/multilingual-e5-small" # 1. 事前に用意した3,000件の日本語文章データを読み込む with open("sentences_3000.json", "r", encoding="utf-8") as f: data = json.load(f) # 2. Embeddingモデルで3,000件の文章をベクトル化(E5モデルの仕様に合わせて "passage: " を付与) model = SentenceTransformer(MODEL_NAME) passages = ["passage: " + item["sentence"] for item in data] embeddings = model.encode(passages, batch_size=128, show_progress_bar=True) # 3. PostgreSQLへ接続してテーブル作成・データ投入 conn = psycopg2.connect( host="localhost", port=5432, database="vector_db", user="postgres", password="secret0001", ) conn.autocommit = True cursor = conn.cursor() cursor.execute("CREATE EXTENSION IF NOT EXISTS vector;") cursor.execute("DROP TABLE IF EXISTS items;") cursor.execute(""" CREATE TABLE items ( id SERIAL PRIMARY KEY, category TEXT, sentence TEXT, embedding VECTOR(384) ); """) rows = [] for item, emb in zip(data, embeddings): vec_str = "[" + ",".join(f"{float(v):.6f}" for v in emb) + "]" rows.append((item["category"], item["sentence"], vec_str)) execute_values( cursor, "INSERT INTO items (category, sentence, embedding) VALUES %s", rows, ) cursor.execute("ANALYZE items;") # 4. 検索用のクエリ文とベクトルを別テーブルに1件保存(検索クエリには "query: " を付与) query_text = "PostgreSQLのインデックスを使ってベクトル検索を高速化する方法" query_emb = model.encode("query: " + query_text) query_vec = "[" + ",".join(f"{float(v):.6f}" for v in query_emb) + "]" cursor.execute("DROP TABLE IF EXISTS query_target;") cursor.execute(""" CREATE TABLE query_target ( q_text TEXT, q_vec VECTOR(384) ); """) cursor.execute( "INSERT INTO query_target VALUES (%s, %s::vector);", (query_text, query_vec), ) cursor.execute("ANALYZE query_target;") cursor.close() conn.close() print("done") スクリプトを実行してデータを入れます。 python insert_data.py Batches: 100%|██████████████████████████████████████████| 24/24 [00:35<00:00, 1.47s/it] done データが入ったので、ここからはpsqlでPostgresにログインして手動でコマンドを実行していきます。 docker exec -it pgvector_pg18_test psql -U postgres -d vector_db vector_db=# SELECT id, category, sentence FROM items WHERE id <= 5 ORDER BY id; id | category | sentence ----+------------------+---------------------------------------------------------------------------- 1 | データベース | vacuumを実行することで不要な領域を回収してテーブルの肥大化を防ぎます。 2 | 経費精算 | 交通費や出張旅費の精算は月末までに領収書を添付して申請してください。 3 | ネットワーク | 社内無線LANに接続する際は専用の証明書を端末にインストールしてください。 4 | コンテナ・Docker | 開発用のデータベース環境はDockerコンテナを使ってローカルで起動できます。 5 | セキュリティ規定 | 業務用アカウントのパスワードは12文字以上で設定し使い回しを避けてください。 (5 rows) vector_db=# SELECT q_text FROM query_target; q_text -------------------------------------------------------------- PostgreSQLのインデックスを使ってベクトル検索を高速化する方法 (1 row) (SELECT q_vec FROM query_target) を条件に使うことで、このクエリ文のベクトルを使った検索ができます。 検証 1. ベクトルデータのサイズとページ配置 まず、入れた384次元のベクトルと日本語の文章がPostgresの中で何バイトくらい使っているのか見てみます。 vector_db=# SELECT vector_dims(embedding) AS dims, pg_column_size(embedding) AS vector_bytes, pg_column_size(items.*) AS total_row_bytes FROM items LIMIT 1; dims | vector_bytes | total_row_bytes ------+--------------+----------------- 384 | 1544 | 1696 (1 row) vector型は1次元あたり4バイト(32-bit float)なので、4 Byte × 384次元 + 8 Byte(ヘッダ) = 1544 Bytesになっています。category や sentence の日本語テキストを合わせるとさらに増え、この例だと1696 Byteです。 続いて、各行がどのページに入っているかを ctid(ページ番号, ページ内の行番号)で見てみます。 vector_db=# SELECT id, ctid, pg_column_size(items.*) AS row_bytes FROM items WHERE id <= 8 ORDER BY id; id | ctid | row_bytes ----+-------+----------- 1 | (0,1) | 1696 2 | (0,2) | 1688 3 | (0,3) | 1700 4 | (0,4) | 1700 5 | (1,1) | 1708 6 | (1,2) | 1704 7 | (1,3) | 1700 8 | (1,4) | 1700 (8 rows) Postgresの1ページはデフォルトで8KB(8,192 Bytes)なので、1行約1,700 Bytesだと1ページに4行((0,1)〜(0,4))入ったところで次のページ (1,1) に移っているのが分かります。 今回は3,000件入れたので、テーブル全体では 3,000 ÷ 4 = 750ページ(6,000 kB)になります。 2. インデックスなし(Seq Scan)と IVFFlat / HNSW の比較 前回の記事のおまけで気になっていた部分の検証です。 3,000件(750ページ)のデータに対して、インデックスなし(Seq Scan)、IVFFlat、HNSW でそれぞれ上位5件を検索し、EXPLAIN (ANALYZE, BUFFERS) で実行時間と読み込んだページ数、検索結果の精度を見てみます。 インデックスなし(Seq Scan) まずはインデックスを貼らずに検索してみます。 vector_db=# SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | category | sentence ------+--------------+------------------------------------------------------------------------------------------------------ 141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) vector_db=# EXPLAIN (ANALYZE, BUFFERS) SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ Limit (cost=838.34..838.35 rows=5 width=188) (actual time=2.227..2.231 rows=5.00 loops=1) Buffers: shared hit=751 InitPlan 1 -> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.003..0.005 rows=1.00 loops=1) Buffers: shared hit=1 -> Sort (cost=837.33..844.83 rows=3000 width=188) (actual time=2.225..2.226 rows=5.00 loops=1) Sort Key: ((items.embedding <=> (InitPlan 1).col1)) Sort Method: top-N heapsort Memory: 27kB Buffers: shared hit=751 -> Seq Scan on items (cost=0.00..787.50 rows=3000 width=188) (actual time=0.023..1.910 rows=3000.00 loops=1) Buffers: shared hit=751 Planning Time: 0.057 ms Execution Time: 2.273 ms (13 rows) Seq Scanなので、items テーブルの750ページとquery_targetの1ページを合わせた751ページ(Buffers: shared hit=751)を読み込んで、3,000件すべてと距離を計算しています。実行時間は2.273 msでした。 検索クエリ(PostgreSQLのインデックスを使ってベクトル検索を高速化する方法)に対して、データベースカテゴリの「PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。」など似た文5件(ID: 141, 1341, 1741, 2541, 2941)が上位5件として返ってきており、これが全件計算したときの正解の5件になります。 IVFFlat インデックス 次に、前回と同じようにIVFFlatインデックスを lists = 100(100個のグループに分割)で作成して検索してみます。 検索時にいくつのグループを調べるかを指定する ivfflat.probesを1と5に変えて実行してみました。 vector_db=# CREATE INDEX items_ivfflat_idx ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); CREATE INDEX vector_db=# SET ivfflat.probes = 1; SET vector_db=# SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | category | sentence ------+--------------+------------------------------------------------------------------------------------------------------ 141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) vector_db=# EXPLAIN (ANALYZE, BUFFERS) SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=17.74..25.56 rows=5 width=188) (actual time=0.036..0.041 rows=5.00 loops=1) Buffers: shared hit=32 InitPlan 1 -> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.003..0.003 rows=1.00 loops=1) Buffers: shared hit=1 -> Index Scan using items_ivfflat_idx on items (cost=16.73..4710.00 rows=3000 width=188) (actual time=0.035..0.040 rows=5.00 loops=1) Order By: (embedding <=> (InitPlan 1).col1) Index Searches: 1 Buffers: shared hit=32 Planning: Buffers: shared hit=1 Planning Time: 0.032 ms Execution Time: 0.051 ms (13 rows) probes = 1のときは、100個に分けたグループのうち一番近い1グループだけを見に行くので、読み込んだバッファ数が751 → 32に激減し、実行時間も2.273 ms → 0.051 msと40倍速くなりました。 今回はAIにサンプル文をまとめて生成してもらったせいか似た文章が多くて偏りがあり、たまたま上位5件とも同じ一番近いグループに入っていたため、probes = 1でも5件すべて正解と一致していました。データにばらつきがあってグループの境界付近に正解が散らばっている場合は、probes = 1だと別グループの正解を取りこぼすことがあります。 続いてivfflat.probes = 5に増やしてみます。 vector_db=# SET ivfflat.probes = 5; SET vector_db=# SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | category | sentence ------+--------------+------------------------------------------------------------------------------------------------------ 141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) vector_db=# EXPLAIN (ANALYZE, BUFFERS) SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=84.64..92.35 rows=5 width=188) (actual time=0.093..0.097 rows=5.00 loops=1) Buffers: shared hit=78 InitPlan 1 -> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.003..0.003 rows=1.00 loops=1) Buffers: shared hit=1 -> Index Scan using items_ivfflat_idx on items (cost=83.62..4710.00 rows=3000 width=188) (actual time=0.092..0.096 rows=5.00 loops=1) Order By: (embedding <=> (InitPlan 1).col1) Index Searches: 1 Buffers: shared hit=78 Planning: Buffers: shared hit=1 Planning Time: 0.032 ms Execution Time: 0.106 ms (13 rows) probes = 5にすると近い5グループを見に行くようになり、読み込むページ数は32 → 78に増えますが、それでも実行時間は0.106 msと、Seq Scan(2.273 ms・751ページ)の20倍以上速くなっています。 なお、IVFFlatのグループ分けはインデックス作成時に乱数で決める部分があるようで、同じデータでもインデックスを作り直すと読み込むページ数などの結果が一致しない場合があります。私も2回目に動かしたときはshared hit=61になりました。後述するHNSWも同様のようです。 簡単に補足です。 近似最近傍探索(ANN)というのは、距離の計算式自体を大雑把に近似しているわけではなく、調べる対象の範囲(グループやグラフの探索範囲)を絞ることで読み込むページ数と計算回数を減らす仕組みです。そのため、探索範囲に入ったデータについてはコサイン距離の数値自体は厳密計算とまったく同じになり、近いグループの中に上位データが収まっていれば順位も数値も変わらない、ということみたいです。これで前回の疑問になっていた部分は検証できたかと思います。 HNSW インデックス 続いて、一度IVFFlatインデックスを消してから、HNSWインデックスを作成して試してみます。 vector_db=# DROP INDEX items_ivfflat_idx; DROP INDEX vector_db=# CREATE INDEX items_hnsw_idx ON items USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64); CREATE INDEX vector_db=# SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | category | sentence ------+--------------+------------------------------------------------------------------------------------------------------ 141 | データベース | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | データベース | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | データベース | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | データベース | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | データベース | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) vector_db=# EXPLAIN (ANALYZE, BUFFERS) SELECT id, category, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=470.69..480.01 rows=5 width=188) (actual time=0.208..0.212 rows=5.00 loops=1) Buffers: shared hit=436 InitPlan 1 -> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.007..0.007 rows=1.00 loops=1) Buffers: shared hit=1 -> Index Scan using items_hnsw_idx on items (cost=469.68..6064.00 rows=3000 width=188) (actual time=0.207..0.210 rows=5.00 loops=1) Order By: (embedding <=> (InitPlan 1).col1) Index Searches: 1 Buffers: shared hit=436 Planning: Buffers: shared hit=1 Planning Time: 0.069 ms Execution Time: 0.229 ms (13 rows) HNSWは5件とも正解と一致し、実行時間は0.229 msでした。 比較のためにIVFFlatももう一度作って、テーブルと各インデックスのサイズも見比べてみます。 vector_db=# CREATE INDEX items_ivfflat_idx ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); CREATE INDEX vector_db=# SELECT relname, pg_size_pretty(pg_relation_size(oid)) AS size FROM pg_class WHERE relname IN ('items', 'items_ivfflat_idx', 'items_hnsw_idx'); relname | size -------------------+--------- items | 6000 kB items_hnsw_idx | 6008 kB items_ivfflat_idx | 5264 kB (3 rows) ここまでの実行時間・バッファ読込数・精度・サイズをまとめると以下のようになりました。 | 検索方法 | 実行時間 | 読込ページ数 (shared hit) | 上位5件の一致数 | インデックスサイズ | | :--- | ---: | ---: | :---: | ---: | | インデックスなし (Seq Scan) | 2.273 ms | 751 | 5 / 5(基準) | - | | IVFFlat (probes = 1) | 0.051 ms | 32 | 5 / 5 | 5264 kB | | IVFFlat (probes = 5) | 0.106 ms | 78 | 5 / 5 | 5264 kB | | HNSW(デフォルト) | 0.229 ms | 436 | 5 / 5 | 6008 kB | IVFFlatは探索するグループ数を絞れるのでバッファ読込数も実行時間もかなり小さく抑えられますが、あらかじめデータが入っている状態で作成しないとグループ分けがうまくいかないという注意点があります。一方、HNSWはデータ追加時にもグラフを繋いでくれてデフォルト設定のまま高い精度が出るので扱いやすいかなと思います。その分、グラフのリンク情報を持つのでインデックスサイズはテーブル本体と同じくらいの大きさ(6008 kB)になっています。 3. 距離計算演算子の比較 前回はコサイン距離(<=>)だけを使いましたが、pgvectorでは全部で6種類の距離計算演算子が用意されています。 | 演算子 | 距離の種類 | 対応する型 | 備考 | | :---: | :--- | :--- | :--- | | <=> | コサイン距離(Cosine) | vector, halfvec, sparsevec | ベクトルの向きの違い(0〜2) | | <-> | L2距離 | vector, halfvec, sparsevec | 2点間の直線距離 | | <#> | 負の内積(Inner Product) | vector, halfvec, sparsevec | 内積にマイナスを掛けた値 | | <+> | L1距離 | vector, halfvec, sparsevec | 各次元の差の絶対値の合計 | | <~> | ハミング距離(Hamming) | bit | 異なるビットの個数 | | <%> | ジャッカード距離(Jaccard) | bit | 集合の重なり具合(0〜1) | 文章のベクトル検索(RAGなど)では、文章の長さや単語の出現回数によってベクトルの大きさ(長さ)が変わっても、ベクトルの向き(意味の方向)がどれくらい近いかを測れるコサイン距離を使うのが一般的です。 なお、Postgresのインデックススキャンは ORDER BY 演算子 ASCで使う仕組みになっているため、内積も似ているほど値が小さくなるように符号を反転させた負の内積(<#>)になっているようです。 ここではvector型で使える4つの演算子(<=>, <->, <#>, <+>)について、以下の2点に着目して比べてみます。 - 各演算子の実行時間(psqlの \timing で計測) - コサイン距離で出てきた上位5件と比べて、他の演算子だとどの文章が近いと判定されるか(検索クエリ「PostgreSQLのインデックスを使ってベクトル検索を高速化する方法」に対する近さ) 純粋な距離計算の時間を比べるため、いったんインデックスを削除し、計測をオンにして4つの演算子を順番に実行してみます。 vector_db=# DROP INDEX items_ivfflat_idx, items_hnsw_idx; DROP INDEX vector_db=# \timing Timing is on. vector_db=# SELECT id, round((embedding <=> (SELECT q_vec FROM query_target))::numeric, 6) AS cosine_dist, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | cosine_dist | sentence ------+-------------+------------------------------------------------------------------------------------------------------ 141 | 0.086783 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | 0.087194 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | 0.091633 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | 0.097568 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | 0.098207 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) Time: 3.897 ms vector_db=# SELECT id, round((embedding <-> (SELECT q_vec FROM query_target))::numeric, 6) AS l2_dist, sentence FROM items ORDER BY embedding <-> (SELECT q_vec FROM query_target) LIMIT 5; id | l2_dist | sentence ------+----------+------------------------------------------------------------------------------------------------------ 141 | 0.416612 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | 0.417598 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | 0.428096 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | 0.441743 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | 0.443185 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) Time: 2.706 ms vector_db=# SELECT id, round((embedding <#> (SELECT q_vec FROM query_target))::numeric, 6) AS neg_ip, sentence FROM items ORDER BY embedding <#> (SELECT q_vec FROM query_target) LIMIT 5; id | neg_ip | sentence ------+-----------+------------------------------------------------------------------------------------------------------ 141 | -0.913217 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | -0.912806 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | -0.908367 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | -0.902432 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | -0.901793 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) Time: 2.695 ms vector_db=# SELECT id, round((embedding <+> (SELECT q_vec FROM query_target))::numeric, 6) AS l1_dist, sentence FROM items ORDER BY embedding <+> (SELECT q_vec FROM query_target) LIMIT 5; id | l1_dist | sentence ------+----------+------------------------------------------------------------------------------------------------ 141 | 6.382686 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | 6.445336 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | 6.559072 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | 6.849228 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 541 | 6.869993 | 社内ルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) Time: 3.595 ms 4つの演算子の実行時間と、上位5件の結果をまとめると以下の通りです。 | 演算子 | 実行時間 | 上位5件のID | コサイン距離との比較 | | :---: | ---: | :--- | :--- | | <=>(コサイン距離) | 3.897 ms | 141, 1341, 1741, 2541, 2941 | 基準(クエリ文に意味が一番近い上位5件) | | <->(L2距離) | 2.706 ms | 141, 1341, 1741, 2541, 2941 | 上位5件・順位ともコサイン距離と完全に一致 | | <#>(負の内積) | 2.695 ms | 141, 1341, 1741, 2541, 2941 | 実行時間が最速で、上位5件・順位ともコサイン距離と完全に一致 | | <+>(L1距離) | 3.595 ms | 141, 1341, 1741, 2941, 541 | 1〜3位は同じだが、4位と5位が入れ替わる | ※文章の比較は一般的にコサイン距離で実施することが多いため、コサイン距離を基準にしています 実行時間で見ると、各次元の掛け算と足し算だけで済む負の内積が2.695 msで一番速く、ベクトルの長さで割る計算が入るコサイン距離が3.897 msと一番時間がかかっています。 また、検索結果の順位を見ると、コサイン距離、L2距離、負の内積の3つが1位から5位までまったく同じ結果になりました。 4. 量子化(halfvec / bit)でどのくらいサイズが下がるか 先ほどHNSWインデックスがテーブル本体と同じくらいのサイズになっていましたが、データ量が増えてきたときにメモリやディスクを節約する機能として、halfvec(16-bit浮動小数点)と binary_quantizeが使えます。 文章検索で一般的なコサイン距離をベースに、元のvector(384)からhalfvec(384)・bit(384)にしたときに、サイズ・実行時間・検索結果がどう変わるかを比べてみました(※ bit型は0と1のビット列でコサイン距離が使えないため、bitのみハミング距離 <~> を使います)。 vector_db=# ALTER TABLE items ADD COLUMN embedding_half halfvec(384), ADD COLUMN embedding_bit bit(384); ALTER TABLE vector_db=# UPDATE items SET embedding_half = embedding::halfvec(384), embedding_bit = binary_quantize(embedding)::bit(384); UPDATE 3000 vector_db=# ANALYZE items; ANALYZE vector_db=# CREATE INDEX items_hnsw_vec_idx ON items USING hnsw (embedding vector_cosine_ops); CREATE INDEX vector_db=# CREATE INDEX items_hnsw_half_idx ON items USING hnsw (embedding_half halfvec_cosine_ops); CREATE INDEX vector_db=# CREATE INDEX items_hnsw_bit_idx ON items USING hnsw (embedding_bit bit_hamming_ops); CREATE INDEX まず、1カラムあたりのバイト数と、HNSWインデックスのサイズを見てみます。 vector_db=# SELECT pg_column_size(embedding) AS vec_bytes, pg_column_size(embedding_half) AS half_bytes, pg_column_size(embedding_bit) AS bit_bytes FROM items LIMIT 1; vec_bytes | half_bytes | bit_bytes -----------+------------+----------- 1540 | 776 | 53 (1 row) vector_db=# SELECT relname, pg_size_pretty(pg_relation_size(oid)) AS index_size FROM pg_class WHERE relname IN ('items_hnsw_vec_idx', 'items_hnsw_half_idx', 'items_hnsw_bit_idx'); relname | index_size ---------------------+------------ items_hnsw_vec_idx | 6008 kB items_hnsw_half_idx | 3440 kB items_hnsw_bit_idx | 1032 kB (3 rows) そして、実行時間を計測しながらそれぞれのインデックスを使って上位5件を検索してみます。 vector_db=# SELECT id, round((embedding <=> (SELECT q_vec FROM query_target))::numeric, 6) AS cosine_dist, sentence FROM items ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | cosine_dist | sentence ------+-------------+------------------------------------------------------------------------------------------------------ 141 | 0.086783 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | 0.087194 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | 0.091633 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | 0.097568 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | 0.098207 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) Time: 0.774 ms vector_db=# SELECT id, round((embedding_half <=> (SELECT q_vec::halfvec(384) FROM query_target))::numeric, 6) AS cosine_dist, sentence FROM items ORDER BY embedding_half <=> (SELECT q_vec::halfvec(384) FROM query_target) LIMIT 5; id | cosine_dist | sentence ------+-------------+------------------------------------------------------------------------------------------------------ 141 | 0.086797 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | 0.087198 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1741 | 0.091638 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2541 | 0.097574 | セキュリティと品質維持のため、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2941 | 0.098213 | 全社共通のルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) Time: 1.045 ms vector_db=# SELECT id, (embedding_bit <~> (SELECT binary_quantize(q_vec)::bit(384) FROM query_target)) AS hamming_dist, sentence FROM items ORDER BY embedding_bit <~> (SELECT binary_quantize(q_vec)::bit(384) FROM query_target) LIMIT 5; id | hamming_dist | sentence ------+--------------+------------------------------------------------------------------------------------------ 1741 | 27 | 基本方針として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 2141 | 27 | 日常業務において、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 141 | 27 | PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 1341 | 27 | 原則として、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 541 | 28 | 社内ルールとして、PostgreSQLでインデックスを作成すると検索クエリの処理が高速になります。 (5 rows) Time: 0.611 ms 結果をまとめると以下のようになりました。 | データ型(演算子) | 1カラムのサイズ | HNSWインデックスサイズ | 実行時間 | vector(コサイン距離)との結果比較 | | :--- | ---: | ---: | ---: | :--- | | vector (<=>) | 1540 Bytes | 6008 kB | 0.774 ms | 基準(上位5件:141, 1341, 1741, 2541, 2941) | | halfvec (<=>) | 776 Bytes | 3440 kB | 1.045 ms | 上位5件・順位とも完全に一致(距離の小数第5位以下のみ微差) | | bit (<~>) | 53 Bytes | 1032 kB | 0.611 ms | 似た文章が上位に入るが、同率(27)が並び順位が入れ替わる | halfvecにすると、カラムサイズもHNSWインデックスのサイズも約半分(6008 kB → 3440 kB)になり、コサイン距離の値も小数第5位以下がほんの少し変わるだけで、検索結果の上位5件は元のvectorとまったく同じでした。実行時間だけ見るとvector(0.774 ms)よりhalfvec(1.045 ms)の方が少し大きくなっていますが、3,000件くらいだとどちらも1ms前後で終わってしまうので、クエリ内の型キャストや実行タイミングの誤差かなと思います(もっと件数大きくしてやり直したいですが大変なので省略)。精度をほぼ落とさずにメモリ・ディスク使用量を半分近く減らせるので、普段使いならhalfvecはかなり良さそうです。 一方、bit型はサイズが53 Bytes(インデックスも約1/6の1032 kB)、実行時間も0.611 msまで下がり、意味が近い「PostgreSQLでインデックスを作成すると〜」の文章群をちゃんと拾えていますが、1次元を正か負かの1ビットに丸めて整数のハミング距離で比較するため、上位4件がすべて距離27で同率になり細かな順位は入れ替わっていました。 5. WHERE句で絞り込んだときの結果0件問題と Iterative Index Scans 最後に、Iterative Index Scans(反復インデックススキャン)を試してみます。 ベクトル検索をするときに WHERE category = 'セキュリティ規定' のようにカテゴリで絞り込みたいケースはよくあると思いますが、HNSWインデックスを使って絞り込み検索をすると、結果が0件になってしまうことがあります。この挙動は hnsw.iterative_scan の設定で切り替えることができます。デフォルトは offです。 今回は全体の5%(3,000件中150件)が該当するcategory = 'セキュリティ規定'という条件で、hnsw.ef_search = 20にして上位5件を検索してみます。 まず hnsw.iterative_scan = off に設定した場合です。 vector_db=# \timing off Timing is off. vector_db=# SET hnsw.ef_search = 20; SET vector_db=# SET hnsw.iterative_scan = off; SET vector_db=# SELECT id, category, sentence FROM items WHERE category = 'セキュリティ規定' ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | category | sentence ----+----------+---------- (0 rows) vector_db=# EXPLAIN (ANALYZE, BUFFERS) SELECT id, category, sentence FROM items WHERE category = 'セキュリティ規定' ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=289.93..526.84 rows=5 width=188) (actual time=0.277..0.278 rows=0.00 loops=1) Buffers: shared hit=290 InitPlan 1 -> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.006..0.007 rows=1.00 loops=1) Buffers: shared hit=1 -> Index Scan using items_hnsw_vec_idx on items (cost=288.92..7396.38 rows=150 width=188) (actual time=0.276..0.277 rows=0.00 loops=1) Order By: (embedding <=> (InitPlan 1).col1) Filter: (category = 'セキュリティ規定'::text) Rows Removed by Filter: 20 Index Searches: 1 Buffers: shared hit=290 Planning: Buffers: shared hit=1 Planning Time: 0.077 ms Execution Time: 0.295 ms (15 rows) iterative_scan = offのときは、まずHNSWインデックスでベクトルが近い上位20件(ef_search = 20)だけを取ってきて、その20件に対して Filter: (category = 'セキュリティ規定') をかけています。上位20件がすべてデータベースカテゴリの文などで埋まっており、セキュリティ規定が1件も含まれていなかったため(Rows Removed by Filter: 20)、テーブル全体には150件あるのに (0 rows) になってしまいました。 次に hnsw.iterative_scan = relaxed_order に切り替えて同じSQLを実行してみます。 vector_db=# SET hnsw.iterative_scan = relaxed_order; SET vector_db=# SELECT id, category, sentence FROM items WHERE category = 'セキュリティ規定' ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; id | category | sentence ------+------------------+-------------------------------------------------------------------------------------------------------------------------------------- 345 | セキュリティ規定 | Webアプリケーションを公開する前には脆弱性診断を実施しSQLインジェクションやXSS対策を確認します。 365 | セキュリティ規定 | パスワードマネージャーを利用してサービスごとに異なるランダムな高強度パスワードを生成・管理します。 1945 | セキュリティ規定 | 基本方針として、Webアプリケーションを公開する前には脆弱性診断を実施しSQLインジェクションやXSS対策を確認します。 1545 | セキュリティ規定 | 原則として、Webアプリケーションを公開する前には脆弱性診断を実施しSQLインジェクションやXSS対策を確認します。 2585 | セキュリティ規定 | セキュリティと品質維持のため、ソースコードや設定ファイルを個人のGitHubアカウントや外部のパブリックリポジトリへ公開してはいけません。 (5 rows) vector_db=# EXPLAIN (ANALYZE, BUFFERS) SELECT id, category, sentence FROM items WHERE category = 'セキュリティ規定' ORDER BY embedding <=> (SELECT q_vec FROM query_target) LIMIT 5; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=289.93..526.84 rows=5 width=188) (actual time=1.501..2.168 rows=5.00 loops=1) Buffers: shared hit=3237 InitPlan 1 -> Seq Scan on query_target (cost=0.00..1.01 rows=1 width=1544) (actual time=0.007..0.008 rows=1.00 loops=1) Buffers: shared hit=1 -> Index Scan using items_hnsw_vec_idx on items (cost=288.92..7396.38 rows=150 width=188) (actual time=1.500..2.165 rows=5.00 loops=1) Order By: (embedding <=> (InitPlan 1).col1) Filter: (category = 'セキュリティ規定'::text) Rows Removed by Filter: 528 Index Searches: 1 Buffers: shared hit=3237 Planning: Buffers: shared hit=1 Planning Time: 0.113 ms Execution Time: 2.192 ms (15 rows) iterative_scan = relaxed_orderに設定すると、ちゃんとセキュリティ規定の中からSQLインジェクション対策などデータベースに近い文章が5件返ってきました。 EXPLAINの結果を見比べると、裏側で何が起きたかがわかります。offのときはRows Removed by Filter: 20(最初の20件を調べて全部弾かれた時点で終了)だったのに対し、relaxed_orderではRows Removed by Filter: 528、rows=5.00となっており、さらに読み込んだページ数もshared hit=290 → 3237に増えています。つまり、最初の20件で見つからなくても探索を打ち切らず、条件に合うデータが LIMIT 5 件集まるまで(合計533件分)インデックスを自動で掘り進めてくれたことが確認できました。 後片付け 一通り検証が終わったら、作成したテーブルを削除してpsqlから抜けます(テーブルに紐づくインデックスも一緒に削除されます)。 vector_db=# DROP TABLE items, query_target; DROP TABLE vector_db=# \q 補足 用語まとめ 最後に、今回の検証やVector Database周りでよく出てくる用語を日本語と英語でまとめておきます。 | 日本語 | 英語 | 説明 | | :--- | :--- | :--- | | 埋め込み / ベクトル化 | Embedding | テキストや画像などの意味を、数百〜数千個の数値の配列(ベクトル)に変換すること。 | | 次元数 | Dimensions | 1つのベクトルに含まれる数値の個数。今回使ったデータは384次元。 | | 正規化 | Normalization | ベクトルの長さを 1 に揃えること。正規化しておくと内積とコサイン距離の順位が同じになる。 | | 最近傍探索(厳密検索) | Exact Nearest Neighbor (ENN) / k-NN | 全データと距離を計算して正確な上位K件を探す方法。インデックスなしの Seq Scan がこれにあたる。 | | 近似最近傍探索 | Approximate Nearest Neighbor (ANN) | 探索する範囲を絞ることで、多少の取りこぼしを許容する代わりに高速に検索する手法。IVFFlat や HNSW が該当する。 | | 再現率 | Recall | 厳密検索での正解上位K件のうち、近似検索で何割を拾えたかを表す指標。 | | 転置ファイルインデックス | IVFFlat (Inverted File Flat) | データをあらかじめ複数のグループ(lists)に分けておき、検索時は近いグループ(probes 個)だけを調べるインデックス。 | | 階層的ナビゲーション可能スモールワールド | HNSW (Hierarchical Navigable Small World) | データを多層のグラフ構造で繋いで探索するインデックス。事前学習なしで高い精度が出やすい。 | | 量子化 | Quantization | 32-bit浮動小数点(vector)をより少ないビット数で表現して、メモリやディスク使用量を減らす手法。 | | 半精度浮動小数点(スカラー量子化) | Half-Precision Float (halfvec) | 1次元を32-bitから16-bit(2バイト)に減らすデータ型。精度をあまり落とさずにサイズを約半分にできる。 | | バイナリ量子化 | Binary Quantization (binary_quantize) | 1次元を正負の 0 か 1(1ビット)に圧縮する手法。データサイズは約1/32になる。 | | 疎ベクトル / 密ベクトル | Sparse Vector (sparsevec) / Dense Vector | ほとんどの要素に値が入っている通常のベクトルが Dense Vector、単語の出現頻度のように大半の要素が 0 のベクトルが Sparse Vector。 | | 再ランキング | Re-ranking | 軽いインデックス(bit など)で多めに候補を取ってきたあと、元の vector などで距離を計算し直して上位K件に並べ替える手法。 | | 反復インデックススキャン | Iterative Index Scans | WHERE 句で絞り込みをしたときに、LIMIT の件数に達するまでインデックス探索を自動で繰り返す機能。 | | ページ(ブロック) | Page / Block | Postgresがディスクやメモリ(shared_buffers)を読み書きする基本単位(デフォルトは8KB)。 | おわりに 前回の記事で疑問に残っていた「なぜ近似検索なのに結果や距離の数値が変わらなかったのか」というところから、pgvectorの各機能まで一通り実機で動かして確認できました。 実際に日本語の文章データを入れてpsqlでEXPLAIN (ANALYZE, BUFFERS)やインデックスのサイズを見ながら動かすと、裏側で何をやっているのかイメージしやすかったです。特にドキュメントを読んだだけではIterative Index Scansの何がIterative(反復)なのか理解できなかったのですが、実際の動きを見たらわかりやすかったです。 なお、今回の検証で試した機能や設定については基本的にすべてpgvector公式GitHubのREADMEに載っているので、細かいパラメータや仕様が気になった方はそちらもあわせて参照してみてください。 pgvectorはもうすぐ 0.9.0が公開されそうです。楽しみですね! 以上です。最後まで読んでいただきありがとうございます! 参考 - pgvector (GitHub) - pgvector/pgvector - 前回の記事:pgvectorで学ぶVector Database(RAGの基礎) - qiita.com
@kartikktwt Benchmark pgvector with the filters your app will use. Its approximate indexes apply filtering after the scan, so selective filters can return fewer rows than LIMIT; iterative scans can help. pgvector/pgvector
The Ultimate Developer Stack: 23 Trending GitHub Repos | 28-10-2026 | Dev Repos Daily cutt.ly 🔥 Nobody Told You About This New AI Repo (Summer2027-Internships) Stay on top of the open source ecosystem with this handpicked selection of trending GitHub repositories. From innovative developer tools to groundbreaking frameworks, these are the projects making waves in the software community right now. October 28, 2026 What is inside this video: - Top 23 trending GitHub repositories ranked by stars gained today - Developer insights and project overviews for every featured repo - AI-narrated walkthrough of each open source project - Direct links to all repositories below for easy access ⏱️ TIMESTAMPS (YouTube Chapters): 00:00 - Intro: Today's High-Impact Tools 00:09 - Trending Leaderboard Overview 00:25 - #1 Summer2027-Internships 00:54 - #2 n8n 01:24 - #3 datahub 01:45 - #4 upscayl 02:08 - #5 free-for-dev 02:33 - #6 awesome-remote-job 02:59 - #7 Data-Science-For-Beginners 03:27 - #8 PowerToys 03:50 - #9 neovim 04:10 - #10 jellyfin 04:33 - #11 llama_index 04:56 - #12 syft 05:18 - #13 playwright 05:46 - #14 plane 06:09 - #15 pgvector 06:28 - #16 awesome 06:59 - #17 runner-images 07:19 - #18 rustdesk 07:43 - #19 lazygit 08:05 - #20 transformers 08:31 - #21 directus 09:02 - #22 gitleaks 09:22 - #23 OpenCore-Legacy-Patcher 09:45 - Outro & Key Takeaways ━━━━━━━━━━━━━━━━━━━━━━━ TODAY'S TOP 23 TRENDING REPOSITORIES: ━━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Summer2027-Internships (⭐ 48.2k • +21 today • Python) Summer 2027 software engineering, data science, AI, quant, product management, and hardware internship postings. Updated daily by Simplify and Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208.9k • +161 today • TypeScript) Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12.9k • +10 today • Python) The Context Platform for your Data and AI Stack 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51.2k • +76 today • TypeScript) 🆙 Upscayl - #1 Free and Open Source AI Image Upscaler for Linux, MacOS and Windows. 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2k • +55 today • HTML) A list of SaaS, PaaS and IaaS offerings that have free tiers of interest to devops and infradev 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 today • Unknown) A curated list of awesome remote jobs and resources. Inspired by vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 today • Jupyter Notebook) 10 Weeks, 20 Lessons, Data Science for All! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140.1k • +84 today • C) Microsoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103.2k • +41 today • Vim Script) Vim-fork focused on extensibility and usability 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58.7k • +74 today • C#) The Free Software Media System - Server Backend & API 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52.7k • +23 today • Python) LlamaIndex is the document processing platform for AI 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9.8k • +14 today • Go) CLI tool and library for generating a Software Bill of Materials from container images and filesystems 🔗 anchore/syft #13 microsoft/playwright (⭐ 98.7k • +90 today • TypeScript) Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61.6k • +64 today • TypeScript) 🔥🔥🔥 Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage. 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23.5k • +17 today • C) Open-source vector similarity search for Postgres 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━━ Subscribe to @devrepos for daily GitHub trending repositories, open source roundups, and developer news. New videos every day covering the best open source software and trending projects on GitHub. [ar] أفضل حزمة أدوات للمطورين: 23 مستودعاً رائجاً على GitHub | 28-10-2026 | مستودعات المطورين اليومية cutt.ly 🔥 لم يخبرك أحد عن هذا المستودع الجديد للذكاء الاصطناعي (تدريب صيفي 2027) ابقَ على اطلاع دائم بأحدث التطورات في عالم البرمجيات مفتوحة المصدر مع هذه المجموعة المختارة بعناية من مستودعات GitHub الرائجة. من أدوات تطوير مبتكرة إلى أطر عمل رائدة، هذه هي المشاريع التي تُحدث ضجة في مجتمع البرمجيات حاليًا. ... ٢٨ أكتوبر ٢٠٢٦ محتوى هذا الفيديو: - أفضل ٢٣ مستودعًا رائجًا على GitHub، مُرتبة حسب عدد النجوم المكتسبة اليوم - رؤى المطورين ونظرة عامة على المشاريع لكل مستودع مميز - شرح صوتي مُعزز بالذكاء الاصطناعي لكل مشروع مفتوح المصدر - روابط مباشرة لجميع المستودعات أدناه لسهولة الوصول ⏱️ الفواصل الزمنية (فصول يوتيوب): ٠٠:٠٠ - مقدمة: أدوات اليوم الأكثر تأثيرًا ٠٠:٠٩ - نظرة عامة على قائمة المتصدرين الرائجة ٠٠:٢٥ - #١ تدريب صيفي ٢٠٢٧ ٠٠:٥٤ - #٢ n8n ٠١:٢٤ - #٣ datahub ٠١:٤٥ - #٤ upscayl ٠٢:٠٨ - #٥ free-for-dev ٠٢:٣٣ - #٦ awesome-remote-job ٠٢:٥٩ - #٧ علوم البيانات للمبتدئين ٠٣:٢٧ - #٨ باور تويز 03:50 - #9 نيوفيم 04:10 - #10 جيلي فين 04:33 - #11 لاما إندكس 04:56 - #12 سيفت 05:18 - #13 بلاي رايت 05:46 - #14 بلين 06:09 - #15 بي جي فيكتور 06:28 - #16 أوسوم 06:59 - #17 رانر إيمجز 07:19 - #18 رست ديسك 07:43 - #19 ليزي جيت 08:05 - #20 ترانسفورمرز 08:31 - #21 دايركت توس 09:02 - #22 جيت ليكس 09:22 - #23 أوبن كور ليجاسي باتشر 09:45 - الخاتمة والمفتاح أهم النقاط ━━━━━━━━━━━━━━━━━━━━━━━━ أفضل 23 موقعًا رائجًا اليوم: ━━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Summer2027-Internships (⭐ 48.2 ألف • +21 اليوم • بايثون) فرص تدريب صيفية لعام 2027 في هندسة البرمجيات، وعلوم البيانات، والذكاء الاصطناعي، والتحليل الكمي، وإدارة المنتجات، والأجهزة. يتم تحديثها يوميًا بواسطة Simplify و Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208.9 ألف • +161 اليوم • TypeScript) منصة أتمتة سير العمل البرمجية العادلة مع إمكانيات ذكاء اصطناعي مدمجة. اجمع بين البناء المرئي والبرمجة المخصصة، مع إمكانية الاستضافة الذاتية أو السحابية، وأكثر من 400 تكامل. منصة أتمتة سير العمل البرمجية العادلة مع إمكانيات الذكاء الاصطناعي المدمجة. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12.9 ألف • +10 اليوم • بايثون) منصة السياق لبياناتك وتقنيات الذكاء الاصطناعي 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51.2 ألف • +76 اليوم • تايب سكريبت) 🆙 Upscayl - برنامج مجاني ومفتوح المصدر لتحسين جودة الصور بتقنية الذكاء الاصطناعي، يعمل على أنظمة لينكس وماك أو إس وويندوز. ... #3 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2 ألف • +55 اليوم • HTML) قائمة بعروض SaaS وPaaS وIaaS التي تتضمن مستويات مجانية تهم مطوري DevOps وInfradev 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50 ألف • +99 اليوم • غير معروف) قائمة منتقاة من أفضل الوظائف والموارد عن بُعد. مستوحى من vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 مايكروسوفت/علوم البيانات للمبتدئين (⭐ 37.8 ألف • +47 اليوم • Jupyter Notebook) 10 أسابيع، 20 درسًا، علوم البيانات للجميع! #7 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140.1 ألف • +84 اليوم • C) مجموعة أدوات Microsoft PowerToys تُعزز الإنتاجية وتُتيح تخصيص نظام Windows. 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103.2 ألف • +41 اليوم • سكربت Vim) نسخة مُعدّلة من Vim تُركز على قابلية التوسع وسهولة الاستخدام. 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58.7 ألف • +74 اليوم • C#) نظام الوسائط البرمجية الحرة - خادم خلفي وواجهة برمجة تطبيقات (API) 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ ٥٢٫٧ ألف • +٢٣ اليوم • بايثون) LlamaIndex هي منصة معالجة المستندات للذكاء الاصطناعي 🔗 run-llama/llama_index #١٢ anchore/syft (⭐ ٩٫٨ ألف • +١٤ اليوم • جو) أداة سطر أوامر ومكتبة لإنشاء قائمة مكونات برمجية من صور الحاويات وأنظمة الملفات 🔗 anchore/syft #١٣ microsoft/playwright (⭐ ٩٨٫٧ ألف • +٩٠ اليوم • تايب سكريبت) Playwright هو إطار عمل لاختبار وأتمتة الويب. يتيح اختبار Chromium وFirefox وWebKit باستخدام واجهة برمجة تطبيقات واحدة. #١٣ microsoft/playwright (⭐ ٩٨٫٧ ألف • +٩٠ اليوم • تايب سكريبت) Playwright هو إطار عمل لاختبار وأتمتة الويب. يتيح اختبار Chromium وFirefox وWebKit باستخدام واجهة برمجة تطبيقات واحدة. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61.6 ألف • +64 اليوم • TypeScript) 🔥🔥🔥 بديل مفتوح المصدر لـ Jira وLinear وMonday وClickUp. Plane منصة حديثة لإدارة المشاريع، تُتيح إدارة المهام، والسباقات، والوثائق، وفرز المهام. Plane 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23.5 ألف • +17 اليوم • C) بحث مفتوح المصدر عن تشابه المتجهات لـ Postgres 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━━ اشترك في @devrepos للاطلاع على أحدث مستودعات GitHub الرائجة، وملخصات المشاريع مفتوحة المصدر، وأخبار المطورين. فيديوهات جديدة يوميًا تغطي أفضل برامج المصادر المفتوحة والمشاريع الرائجة على GitHub. [bn] ডেভেলপারদের জন্য সেরা কালেকশন: ২৩টি ট্রেন্ডিং গিটহাব রিপোজিটরি | ২৮-১০-২০২৬ | ডেভ রিপোস ডেইলি cutt.ly 🔥 এই নতুন এআই রিপোটির কথা আপনাকে কেউ বলেনি (সামার ২০২৭-ইন্টার্নশিপ) ট্রেন্ডিং গিটহাব রিপোজিটরিগুলোর এই বিশেষভাবে নির্বাচিত সংগ্রহের মাধ্যমে ওপেন সোর্স ইকোসিস্টেমের সাথে আপ-টু-ডেট থাকুন। উদ্ভাবনী ডেভেলপার টুলস থেকে শুরু করে যুগান্তকারী ফ্রেমওয়ার্ক পর্যন্ত, এই প্রজেক্টগুলোই এখন সফটওয়্যার কমিউনিটিতে আলোড়ন সৃষ্টি করছে। ২৮শে অক্টোবর, ২০২৬ এই ভিডিওতে যা আছে: আজ অর্জিত স্টারের ভিত্তিতে র্যাঙ্ক করা শীর্ষ ২৩টি ট্রেন্ডিং গিটহাব রিপোজিটরি - প্রতিটি ফিচার করা রিপোর জন্য ডেভেলপারদের মতামত এবং প্রজেক্টের সংক্ষিপ্ত বিবরণ - প্রতিটি ওপেন সোর্স প্রজেক্টের AI-বর্ণিত ওয়াকথ্রু - সহজে অ্যাক্সেসের জন্য নিচে সমস্ত রিপোজিটরির সরাসরি লিঙ্ক ⏱️ টাইমস্ট্যাম্প (ইউটিউব চ্যাপ্টার): ০০:০০ - ভূমিকা: আজকের হাই-ইমপ্যাক্ট টুলস ০০:০৯ - ট্রেন্ডিং লিডারবোর্ডের সংক্ষিপ্ত বিবরণ ০০:২৫ - #১ Summer2027-Internships ০০:৫৪ - #২ n8n ০১:২৪ - #৩ datahub ০১:৪৫ - #৪ upscayl ০২:০৮ - #৫ free-for-dev ০২:৩৩ - #৬ awesome-remote-job ০২:৫৯ - #৭ Data-Science-For-Beginners ০৩:২৭ - #৮ পাওয়ারটয়েজ ০৩:৫০ - #৯ নিওভিম ০৪:১০ - #১০ জেলিফিন ০৪:৩৩ - #১১ লামা_ইনডেক্স ০৪:৫৬ - #১২ সাইফট ০৫:১৮ - #১৩ প্লেরাইট ০৫:৪৬ - #১৪ প্লেন ০৬:০৯ - #১৫ পিজিভেক্টর ০৬:২৮ - #১৬ অসাম ০৬:৫৯ - #১৭ রানার-ইমেজেস ০৭:১৯ - #১৮ রাস্টডেস্ক ০৭:৪৩ - #১৯ লেজিগিট ০৮:০৫ - #২০ ট্রান্সফর্মার্স ০৮:৩১ - #২১ ডিরেক্টাস ০৯:০২ - #২২ গিটলিকস ০৯:২২ - #২৩ ওপেনকোর-লেগ্যাসি-প্যাচার ০৯:৪৫ - আউটরো ও কী মূল কথা ━━━━━━━━━━━━━━━━━━━━━━━ আজকের শীর্ষ ২৩টি ট্রেন্ডিং রিপোজিটরি: ━━━━━━━━━━━━━━━━━━━━━━ #১ SimplifyJobs/Summer2027-Internships (⭐ ৪৮.২ হাজার • আজ +২১ • পাইথন) সামার ২০২৭ সফটওয়্যার ইঞ্জিনিয়ারিং, ডেটা সায়েন্স, এআই, কোয়ান্ট, প্রোডাক্ট ম্যানেজমেন্ট, এবং হার্ডওয়্যার ইন্টার্নশিপের পোস্ট। Simplify এবং Pitt CSC দ্বারা প্রতিদিন আপডেট করা হয়। 🔗 SimplifyJobs/Summer2027-Internships #২ n8n-io/n8n (⭐ ২০৮.৯ হাজার • আজ +১৬১ • টাইপস্ক্রিপ্ট) নেটিভ এআই সক্ষমতাসহ ফেয়ার-কোড ওয়ার্কফ্লো অটোমেশন প্ল্যাটফর্ম। ভিজ্যুয়াল বিল্ডিংয়ের সাথে কাস্টম কোড, সেলফ-হোস্ট বা ক্লাউড, ৪০০+ ইন্টিগ্রেশন একত্রিত করুন। 🔗 n8n-io/n8n #৩ datahub-project/datahub (⭐ ১২.৯ হাজার • আজ +১০ • পাইথন) আপনার ডেটা এবং এআই স্ট্যাকের জন্য কনটেক্সট প্ল্যাটফর্ম। 🔗 datahub-project/datahub #৪ upscayl/upscayl (⭐ ৫১.২ হাজার • আজ +৭৬ • টাইপস্ক্রিপ্ট) 🆙 Upscayl - লিনাক্স, ম্যাকওএস এবং উইন্ডোজের জন্য #১ ফ্রি এবং ওপেন সোর্স এআই ইমেজ আপস্কেলার। 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2k • আজ +55 • HTML) SaaS, PaaS এবং IaaS অফারগুলির একটি তালিকা, যেগুলির ফ্রি টিয়ার রয়েছে এবং যা ডেভঅপ্স ও ইনফ্রাডেভের জন্য আকর্ষণীয়। 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50k • আজ +99 • অজানা) চমৎকার রিমোট চাকরি এবং রিসোর্সের একটি সংকলিত তালিকা। vinta/awesome-python দ্বারা অনুপ্রাণিত 🔗 lukasz-madon/awesome-remote-job #৭ microsoft/Data-Science-For-Beginners (⭐ ৩৭.৮ হাজার • আজ +৪৭ • জুপিটার নোটবুক) ১০ সপ্তাহ, ২০টি পাঠ, সকলের জন্য ডেটা সায়েন্স! 🔗 microsoft/Data-Science-For-Beginners #৮ microsoft/PowerToys (⭐ ১৪০.১ হাজার • আজ +৮৪ • C) মাইক্রোসফট পাওয়ারটয়েজ হলো ইউটিলিটিগুলোর একটি সংগ্রহ যা উইন্ডোজে উৎপাদনশীলতা এবং কাস্টমাইজেশনকে দারুণভাবে বাড়িয়ে তোলে। 🔗 microsoft/PowerToys #৯ neovim/neovim (⭐ ১০৩.২ হাজার • আজ +৪১ • Vim Script) এক্সটেনসিবিলিটি এবং ব্যবহারযোগ্যতার উপর দৃষ্টি নিবদ্ধ একটি ভিম-ফর্ক। 🔗 neovim/neovim #১০ jellyfin/jellyfin (⭐ ৫৮.৭ হাজার • আজ +৭৪ • C#) ফ্রি সফটওয়্যার মিডিয়া সিস্টেম - সার্ভার ব্যাকএন্ড এবং এপিআই। 🔗 jellyfin/jellyfin #১১ run-llama/llama_index (⭐ ৫২.৭ হাজার • আজ +২৩) • পাইথন) লামা ইনডেক্স (LlamaIndex) হলো এআই (AI)-এর জন্য ডকুমেন্ট প্রসেসিং প্ল্যাটফর্ম 🔗 run-llama/llama_index #১২ অ্যাঙ্কোর/সিফট (⭐ ৯.৮ হাজার • আজ +১৪ • গো) কন্টেইনার ইমেজ এবং ফাইলসিস্টেম থেকে সফটওয়্যার বিল অফ মেটেরিয়ালস (Software Bill of Materials) তৈরি করার জন্য একটি সিএলআই (CLI) টুল এবং লাইব্রেরি 🔗 anchore/syft #১৩ মাইক্রোসফট/প্লেরাইট (⭐ ৯৮.৭ হাজার • আজ +৯০ • টাইপস্ক্রিপ্ট) প্লেরাইট (Playwright) হলো ওয়েব টেস্টিং এবং অটোমেশনের জন্য একটি ফ্রেমওয়ার্ক। এটি একটিমাত্র এপিআই (API) দিয়ে ক্রোমিয়াম (Chromium), ফায়ারফক্স (Firefox) এবং ওয়েবকিট (WebKit) পরীক্ষা করার সুযোগ দেয়। 🔗 microsoft/playwright #১৪ মেকপ্লেন/প্লেন (⭐ ৬১.৬ হাজার • আজ +৬৪ • টাইপস্ক্রিপ্ট) 🔥🔥🔥 ওপেন-সোর্স জিরা (Jira), লিনিয়ার (Linear), মানডে (Monday), এবং ক্লিকআপ (ClickUp)-এর বিকল্প। প্লেন হলো টাস্ক, স্প্রিন্ট, ডক্স এবং ট্রায়েজ পরিচালনার জন্য একটি আধুনিক প্রজেক্ট ম্যানেজমেন্ট প্ল্যাটফর্ম। 🔗 makeplane/plane #15 pgvector/pgvector (⭐ ২৩.৫ হাজার • আজ +১৭ • C) পোস্টগ্রেসের জন্য ওপেন-সোর্স ভেক্টর সিমিলারিটি সার্চ 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━ প্রতিদিনের গিটহাব ট্রেন্ডিং রিপোজিটরি, ওপেন সোর্স রাউন্ডআপ এবং ডেভেলপার নিউজের জন্য @devrepos-এ সাবস্ক্রাইব করুন। প্রতিদিন গিটহাবের সেরা ওপেন সোর্স সফটওয়্যার এবং ট্রেন্ডিং প্রজেক্টগুলো নিয়ে নতুন ভিডিও আসে। [de-DE] Der ultimative Entwickler-Stack: 23 angesagte GitHub-Repos | 28.10.2026 | Dev Repos Daily cutt.ly 🔥 Dieses neue KI-Repository ist noch ein Geheimtipp (Sommer 2027 – Praktika) Bleiben Sie mit dieser handverlesenen Auswahl angesagter GitHub-Repositories immer auf dem Laufenden im Open-Source-Ökosystem. Von innovativen Entwicklertools bis hin zu bahnbrechenden Frameworks – diese Projekte begeistern die Software-Community geradezu. 28. Oktober 2026 Inhalt dieses Videos: - Die 23 beliebtesten GitHub-Repositories, sortiert nach den heute erhaltenen Sternen - Entwickler-Einblicke und Projektübersichten zu jedem vorgestellten Repository - KI-gestützter Rundgang durch jedes Open-Source-Projekt - Direkte Links zu allen Repositories für einfachen Zugriff ⏱️ ZEITSTEMPEL (YouTube-Kapitel): 00:00 - Intro: Die wichtigsten Tools von heute 00:09 - Übersicht der beliebtesten Repositories 00:25 - #1 Sommer 2027 – Praktika 00:54 - #2 n8n 01:24 - #3 datahub 01:45 - #4 upscayl 02:08 - #5 free-for-dev 02:33 - #6 awesome-remote-job 02:59 - #7 Data-Science-For-Beginners 03:27 - #8 PowerToys 03:50 – #9 neovim 04:10 – #10 jellyfin 04:33 – #11 llama_index 04:56 – #12 syft 05:18 – #13 playwright 05:46 – #14 plane 06:09 – #15 pgvector 06:28 – #16 awesome 06:59 – #17 runner-images 07:19 – #18 rustdesk 07:43 – #19 lazygit 08:05 – #20 transformers 08:31 – #21 directus 09:02 – #22 gitleaks 09:22 – #23 OpenCore-Legacy-Patcher 09:45 – Abspann & Legende Wichtigste Erkenntnisse ━━━━━━━━━━━━━━━━━━━━━━━ Die 23 beliebtesten Jobportale von heute: ━━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Sommer 2027 – Praktika (⭐ 48,2k • +21 heute • Python) Stellenangebote für Praktika im Bereich Softwareentwicklung, Data Science, KI, Quantitative Methoden, Produktmanagement und Hardware im Sommer 2027. Täglich aktualisiert von Simplify und Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208,9k • +161 heute • TypeScript) Fair-Code-Workflow-Automatisierungsplattform mit nativen KI-Funktionen. Visuelles Erstellen mit benutzerdefiniertem Code kombinieren, selbst hosten oder in der Cloud, über 400 Integrationen. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12,9k • +10 heute • Python) Die Kontextplattform für Ihren Daten- und KI-Stack. 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51,2k • +76 heute • TypeScript) 🆙 Upscayl – Nr. 1 kostenloser Open-Source-KI-Bild-Upscaler für Linux, macOS und Windows. 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.200 • +55 heute • HTML) Eine Liste von SaaS-, PaaS- und IaaS-Angeboten mit kostenlosen Tarifen, die für DevOps- und Infrastrukturentwickler interessant sind. 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50.000 • +99 heute • Unbekannt) Eine kuratierte Liste mit tollen Remote-Jobs und Ressourcen. Inspiriert von vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Data-Science-For-Beginners (⭐ 37,8k • +47 heute • Jupyter Notebook) 10 Wochen, 20 Lektionen: Data Science für alle! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140,1k • +84 heute • C) Microsoft PowerToys ist eine Sammlung von Hilfsprogrammen, die die Produktivität und Anpassungsmöglichkeiten unter Windows deutlich verbessern. 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103,2k • +41 heute • Vim Script) Vim-Fork mit Fokus auf Erweiterbarkeit und Benutzerfreundlichkeit. 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58,7k • +74 heute • C#) Das Free Software Media System – Server-Backend & API 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52,7k • +23 heute • Python) LlamaIndex ist die Dokumentenverarbeitungsplattform für KI. 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9,8k • +14 heute • Go) CLI-Tool und Bibliothek zur Generierung einer Software-Stückliste aus Container-Images und Dateisystemen. 🔗 anchore/syft #13 microsoft/playwright (⭐ 98,7k • +90 heute • TypeScript) Playwright ist ein Framework für Webtests und -automatisierung. Es ermöglicht das Testen von Chromium, Firefox und WebKit mit einer einzigen API. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61,6k • +64 heute • TypeScript) 🔥🔥🔥 Plane ist eine Open-Source-Alternative zu Jira, Linear, Monday und ClickUp. Es handelt sich um eine moderne Projektmanagement-Plattform zur Verwaltung von Aufgaben, Sprints, Dokumenten und Priorisierung. 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23,5k • +17 heute • C) Open-Source-Vektorähnlichkeitssuche für PostgreSQL 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━━━ Abonniere @devrepos für täglich aktuelle GitHub-Repositories, Open-Source-Übersichten und Entwickler-News. Täglich neue Videos zu den besten Open-Source-Softwareprojekten und Trendprojekten auf GitHub. [es-US] El stack definitivo para desarrolladores: 23 repositorios de GitHub en tendencia | 28/10/2026 | D... cutt.ly 🔥 Nadie te habló de este nuevo repositorio de IA (Prácticas de verano de 2027) Mantente al día con el ecosistema de código abierto con esta selección de repositorios de GitHub que marcan tendencia. Desde herramientas innovadoras para desarrolladores hasta frameworks revolucionarios, estos son los proyectos que están causando sensación en la comunidad de software. 28 de octubre de 2026 Contenido de este video: - Los 23 repositorios de GitHub más populares, clasificados según las estrellas obtenidas hoy. - Información para desarrolladores y descripciones generales de cada repositorio destacado. - Tutorial guiado por IA de cada proyecto de código abierto. - Enlaces directos a todos los repositorios a continuación para un acceso fácil. ⏱️ MARCAS DE TIEMPO (Capítulos de YouTube): 00:00 - Introducción: Herramientas de alto impacto de hoy 00:09 - Resumen de la clasificación de tendencias 00:25 - N.° 1: Prácticas de verano de 2027 00:54 - N.° 2: n8n 01:24 - N.° 3: datahub 01:45 - N.° 4: upscayl 02:08 - N.° 5: free-for-dev 02:33 - N.° 6: awesome-remote-job 02:59 - N.° 7: Ciencia de datos para principiantes 03:27 - N.° 8 PowerToys 03:50 - #9 neovim 04:10 - #10 jellyfin 04:33 - #11 llama_index 04:56 - #12 syft 05:18 - #13 playwright 05:46 - #14 plane 06:09 - #15 pgvector 06:28 - #16 awesome 06:59 - #17 runner-images 07:19 - #18 rustdesk 07:43 - #19 lazygit 08:05 - #20 transformers 08:31 - #21 directus 09:02 - #22 gitleaks 09:22 - #23 OpenCore-Legacy-Patcher 09:45 - Outro y clave Conclusiones ━━━━━━━━━━━━━━━━━━━━━━━ LOS 23 REPOSITORIOS MÁS POPULARES DE HOY: ━━━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Summer2027-Interships (⭐ 48.2k • +21 hoy • Python) Ofertas de prácticas de verano de 2027 en ingeniería de software, ciencia de datos, IA, análisis cuantitativo, gestión de productos y hardware. Actualizado diariamente por Simplify y Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208.9k • +161 hoy • TypeScript) Plataforma de automatización de flujos de trabajo con código justo y capacidades de IA nativas. Combina la creación visual con código personalizado, autoalojamiento o en la nube, más de 400 integraciones. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12.9k • +10 hoy • Python) La plataforma de contexto para tu pila de datos e IA. 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51.2k • +76 hoy • TypeScript) 🆙 Upscayl: el escalador de imágenes con IA gratuito y de código abierto n.° 1 para Linux, macOS y Windows. 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2k • +55 hoy • HTML) Una lista de ofertas de SaaS, PaaS e IaaS con planes gratuitos de interés para devops e infradev. 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 hoy • Desconocido) Una lista seleccionada de excelentes trabajos y recursos remotos. Inspirado en vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Ciencia de Datos para Principiantes (⭐ 37.8k • +47 hoy • Jupyter Notebook) 10 semanas, 20 lecciones: ¡Ciencia de Datos para todos! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140.1k • +84 hoy • C) Microsoft PowerToys es una colección de utilidades que potencian la productividad y la personalización en Windows. 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103.2k • +41 hoy • Vim Script) Bifurcación de Vim centrada en la extensibilidad y la usabilidad. 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58.7k • +74 hoy • C#) Sistema de medios de software libre: backend y API del servidor. 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52.7k • +23 hoy • Python) LlamaIndex es la plataforma de procesamiento de documentos para IA. 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9.8k • +14 hoy • Go) Herramienta y biblioteca de línea de comandos para generar una lista de materiales de software a partir de imágenes de contenedores y sistemas de archivos. 🔗 anchore/syft #13 microsoft/playwright (⭐ 98.7k • +90 hoy • TypeScript) Playwright es un framework para pruebas y automatización web. Permite probar Chromium, Firefox y WebKit con una única API. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61.6k • +64 hoy • TypeScript) 🔥🔥🔥 Alternativa de código abierto a Jira, Linear, Monday y ClickUp. Plane es una plataforma moderna de gestión de proyectos para administrar tareas, sprints, documentación y priorización de tareas. 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23.5k • +17 hoy • C) Búsqueda de similitud vectorial de código abierto para PostgreSQL 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━━━ Suscríbete a @devrepos para ver diariamente los repositorios más populares de GitHub, resúmenes de código abierto y noticias para desarrolladores. Nuevos videos cada d... [fr-FR] Le stack ultime du développeur : 23 dépôts GitHub en vogue | 28/10/2026 | Dev Repos Daily cutt.ly 🔥 Personne ne vous a parlé de ce nouveau dépôt d'IA (Stages été 2027) Restez à la pointe de l'écosystème open source grâce à cette sélection exclusive de dépôts GitHub incontournables. Des outils de développement innovants aux frameworks révolutionnaires, découvrez les projets qui font sensation dans la communauté du logiciel en ce moment. 28 octobre 2026 Contenu de cette vidéo : - Les 23 dépôts GitHub les plus populaires, classés par nombre d'étoiles gagnées aujourd'hui - Présentations et analyses de chaque dépôt mis en avant - Visite guidée commentée par une IA de chaque projet open source - Liens directs vers tous les dépôts ci-dessous pour un accès facile ⏱️ HORODATAGE (Chapitres YouTube) : 00:00 - Introduction : Les outils à fort impact du jour 00:09 - Aperçu du classement des tendances 00:25 - N° 1 Summer2027-Internships 00:54 - N° 2 n8n 01:24 - N° 3 datahub 01:45 - N° 4 upscayl 02:08 - N° 5 free-for-dev 02:33 - N° 6 awesome-remote-job 02:59 - N° 7 Data-Science-For-Beginners 03:27 - N° 8 PowerToys 03:50 - #9 neovim 04:10 - #10 jellyfin 04:33 - #11 llama_index 04:56 - #12 syft 05:18 - #13 playwright 05:46 - #14 plane 06:09 - #15 pgvector 06:28 - #16 awesome 06:59 - #17 runner-images 07:19 - #18 rustdesk 07:43 - #19 lazygit 08:05 - #20 transformers 08:31 - #21 directus 09:02 - #22 gitleaks 09:22 - #23 OpenCore-Legacy-Patcher 09:45 - Conclusion et légende Points clés ━━━━━━━━━━━━━━━━━━━━━━ TOP 23 DES DÉPÔTS LES PLUS CONSULTÉS AUJOURD'HUI : ━━━━━━━━━━━━━━━━━━━━━━━ N° 1 SimplifyJobs/Stages Été 2027 (⭐ 48,2 k • +21 aujourd'hui • Python) Offres de stage Été 2027 en génie logiciel, science des données, IA, analyse quantitative, gestion de produits et matériel informatique. Mise à jour quotidienne par Simplify et Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208,9 k • +161 aujourd'hui • TypeScript) Plateforme d'automatisation des flux de travail FairCode avec des fonctionnalités d'IA natives. Combinez la création visuelle avec du code personnalisé, auto-hébergé ou cloud, plus de 400 intégrations. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12,9 k • +10 aujourd'hui • Python) La plateforme Context pour votre stack de données et d'IA 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51,2 k • +76 aujourd'hui • TypeScript) 🆙 Upscayl - Upscaler d'images IA gratuit et open source n° 1 pour Linux, macOS et Windows. 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140,2 k • +55 aujourd'hui • HTML) Liste d'offres SaaS, PaaS et IaaS proposant des versions gratuites intéressantes pour les développeurs DevOps et Infrastructure. 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50 k • +99 aujourd'hui • Inconnu) Sélection d'offres d'emploi et de ressources intéressantes pour le télétravail. Inspiré par vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Data-Science-For-Beginners (⭐ 37,8 k • +47 aujourd'hui • Jupyter Notebook) 10 semaines, 20 leçons : la science des données pour tous ! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140,1 k • +84 aujourd'hui • C) Microsoft PowerToys est une collection d'utilitaires qui optimisent la productivité et la personnalisation sous Windows. 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103,2 k • +41 aujourd'hui • Script Vim) Une version dérivée de Vim axée sur l'extensibilité et la facilité d'utilisation. 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58,7 k • +74 aujourd'hui • C#) Le système de gestion de médias de logiciels libres : serveur et API. 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52,7 k • +23 aujourd'hui • Python) LlamaIndex est une plateforme de traitement de documents pour l'IA. 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9,8 k • +14 aujourd'hui • Go) Outil et bibliothèque en ligne de commande pour générer une nomenclature logicielle à partir d'images de conteneurs et de systèmes de fichiers. 🔗 anchore/syft #13 microsoft/playwright (⭐ 98,7 k • +90 aujourd'hui • TypeScript) Playwright est un framework pour les tests et l'automatisation web. Il permet de tester Chromium, Firefox et WebKit avec une API unique. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61,6 k • +64 aujourd'hui • TypeScript) 🔥🔥🔥 Alternative open source à Jira, Linear, Monday et ClickUp. Plane est une plateforme moderne de gestion de projet permettant de gérer les tâches, les sprints, la documentation et le triage. 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23,5 k • +17 aujourd'hui • C) Outil open source de recherche de similarité vectorielle pour Postgres 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━ Abonnez-vous à @devrepos pour découvrir chaque jour les dépôts GitHub les plus ... [hi] बेहतरीन डेवलपर स्टैक: 23 ट्रेंडिंग GitHub रिपोज़ | 28-10-2026 | डेव रिपोज़ डेली cutt.ly 🔥 इस नए AI रिपॉजिटरी के बारे में आपको किसी ने नहीं बताया (ग्रीष्म 2027 - इंटर्नशिप) ओपन सोर्स इकोसिस्टम की नवीनतम जानकारी के लिए GitHub के इन चुनिंदा रिपॉजिटरी का इस्तेमाल करें। इनोवेटिव डेवलपर टूल्स से लेकर क्रांतिकारी फ्रेमवर्क तक, ये वो प्रोजेक्ट हैं जो सॉफ्टवेयर जगत में धूम मचा रहे हैं। 28 अक्टूबर, 2026 इस वीडियो में क्या है: - आज प्राप्त स्टार रेटिंग के आधार पर शीर्ष 23 ट्रेंडिंग GitHub रिपॉजिटरी - प्रत्येक प्रदर्शित रिपॉजिटरी के लिए डेवलपर अंतर्दृष्टि और प्रोजेक्ट अवलोकन - प्रत्येक ओपन सोर्स प्रोजेक्ट का AI-नैरेटेड वॉकथ्रू - आसान पहुँच के लिए नीचे सभी रिपॉजिटरी के सीधे लिंक ⏱️ टाइमस्टैम्प (YouTube अध्याय): 00:00 - परिचय: आज के उच्च-प्रभाव वाले उपकरण 00:09 - ट्रेंडिंग लीडरबोर्ड अवलोकन 00:25 - #1 समर 2027 इंटर्नशिप 00:54 - #2 n8n 01:24 - #3 datahub 01:45 - #4 upscayl 02:08 - #5 फ्री-फॉर-डेव 02:33 - #6 शानदार रिमोट जॉब 02:59 - #7 डेटा साइंस फॉर बिगिनर्स 03:27 - #8 पॉवर टॉयज़ 03:50 - #9 नेओविम 04:10 - #10 जेलीफिन 04:33 - #11 लामा_इंडेक्स 04:56 - #12 सिफ्ट 05:18 - #13 प्लेराइट 05:46 - #14 प्लेन 06:09 - #15 पीजीवेक्टर 06:28 - #16 ऑसम 06:59 - #17 रनर-इमेजेज 07:19 - #18 रस्टडेस्क 07:43 - #19 लेज़ीगिट 08:05 - #20 ट्रांसफॉर्मर्स 08:31 - #21 डायरेक्टस 09:02 - #22 गिटलीक्स 09:22 - #23 ओपनकोर-लेगेसी-पैचर 09:45 - आउट्रो और कुंजी मुख्य बिंदु ━━━━━━━━━━━━━━━━━━━━━━━━ आज के शीर्ष 23 ट्रेंडिंग रिपॉजिटरी: ━━━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Summer2027-इंटर्नशिप (⭐ 48.2k • आज +21 • पायथन) ग्रीष्मकालीन 2027 के लिए सॉफ्टवेयर इंजीनियरिंग, डेटा साइंस, एआई, क्वांट, प्रोडक्ट मैनेजमेंट और हार्डवेयर इंटर्नशिप के अवसर। Simplify और Pitt CSC द्वारा प्रतिदिन अपडेट किया जाता है। 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208.9k • आज +161 • TypeScript) नेटिव AI क्षमताओं वाला फेयर-कोड वर्कफ़्लो ऑटोमेशन प्लेटफ़ॉर्म। विज़ुअल बिल्डिंग को कस्टम कोड के साथ मिलाएं, सेल्फ-होस्ट या क्लाउड का उपयोग करें, 400+ इंटीग्रेशन उपलब्ध हैं। 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12.9k • आज +10 • Python) आपके डेटा और AI स्टैक के लिए कॉन्टेक्स्ट प्लेटफ़ॉर्म 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51.2k • आज +76 • TypeScript) 🆙 Upscayl - Linux, MacOS और Windows के लिए नंबर 1 मुफ़्त और ओपन सोर्स AI इमेज अपस्केलर। 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2k • आज +55 • HTML) SaaS, PaaS और IaaS सेवाओं की एक सूची जिनमें DevOps और InfraDevelop के लिए उपयोगी निःशुल्क विकल्प उपलब्ध हैं। 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50k • आज +99 • अज्ञात) शानदार रिमोट जॉब्स और संसाधनों की एक चुनिंदा सूची। vinta/awesome-python से प्रेरित 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • आज +47 • Jupyter Notebook) 10 सप्ताह, 20 पाठ, सभी के लिए डेटा साइंस! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140.1k • आज +84 • C) Microsoft PowerToys यूटिलिटीज़ का एक संग्रह है जो Windows पर उत्पादकता और अनुकूलन को बढ़ाता है। 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103.2k • आज +41 • Vim Script) विस्तारशीलता और उपयोगिता पर केंद्रित Vim-फोर्क 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58.7k • आज +74 • C#) फ्री सॉफ्टवेयर मीडिया सिस्टम - सर्वर बैकएंड और API 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52.7k • आज +23 • Python) LlamaIndex एक AI-आधारित दस्तावेज़ प्रसंस्करण प्लेटफ़ॉर्म है। 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9.8k • आज +14 • Go) कंटेनर इमेज और फ़ाइल सिस्टम से सॉफ़्टवेयर बिल ऑफ़ मैटेरियल्स जनरेट करने के लिए एक CLI टूल और लाइब्रेरी। 🔗 anchore/syft #13 microsoft/playwright (⭐ 98.7k • आज +90 • TypeScript) Playwright वेब टेस्टिंग और ऑटोमेशन के लिए एक फ़्रेमवर्क है। यह एक ही API के साथ Chromium, Firefox और WebKit की टेस्टिंग की सुविधा देता है। 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61.6k • आज +64 • TypeScript) 🔥🔥🔥 ओपन-सोर्स Jira, Linear, Monday और ClickUp का विकल्प। Plane एक आधुनिक प्रोजेक्ट मैनेजमेंट प्लेटफॉर्म है जिसका उपयोग टास्क, स्प्रिंट, डॉक्स और ट्राइएज को मैनेज करने के लिए किया जाता है। 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23.5k • आज +17 • C) पोस्टग्रेस के लिए ओपन-सोर्स वेक्टर समानता खोज 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━━━ दैनिक GitHub ट्रेंडिंग रिपॉजिटरी, ओपन सोर्स राउंडअप और डेवलपर समाचारों के लिए @devrepos को सब्सक्राइब करें। GitHub पर सर्वश्रेष्ठ ओपन सोर्स सॉफ़्टवेयर और ट्रेंडिंग प्रोजेक्ट्स को कवर करने वाले नए वीडियो हर दिन देखें। [id] Tumpukan Perangkat Lunak Pengembang Terbaik: 23 Repositori GitHub Terpopuler | 28-10-2026 | Dev R... cutt.ly 🔥 Belum Ada yang Memberitahu Anda Tentang Repositori AI Baru Ini (Magang Musim Panas 2027) Tetap terhubung dengan ekosistem open source dengan pilihan repositori GitHub yang sedang tren ini. Dari alat pengembang yang inovatif hingga kerangka kerja yang inovatif, ini adalah proyek-proyek yang sedang membuat gebrakan di komunitas perangkat lunak saat ini. 28 Oktober 2026 Isi video ini: - 23 repositori GitHub terpopuler yang diurutkan berdasarkan bintang yang diperoleh hari ini - Wawasan pengembang dan ikhtisar proyek untuk setiap repositori unggulan - Panduan yang dinarasikan AI untuk setiap proyek sumber terbuka - Tautan langsung ke semua repositori di bawah ini untuk akses mudah ⏱️ CAP WAKTU (Bab YouTube): 00:00 - Pendahuluan: Alat-alat Berdampak Tinggi Hari Ini 00:09 - Ikhtisar Papan Peringkat Terpopuler 00:25 - #1 Magang Musim Panas 2027 00:54 - #2 n8n 01:24 - #3 datahub 01:45 - #4 upscayl 02:08 - #5 free-for-dev 02:33 - #6 awesome-remote-job 02:59 - #7 Ilmu Data untuk Pemula 03:27 - #8 PowerToys 03:50 - #9 neovim 04:10 - #10 jellyfin 04:33 - #11 llama_index 04:56 - #12 syft 05:18 - #13 playwright 05:46 - #14 plane 06:09 - #15 pgvector 06:28 - #16 awesome 06:59 - #17 runner-images 07:19 - #18 rustdesk 07:43 - #19 lazygit 08:05 - #20 transformers 08:31 - #21 directus 09:02 - #22 gitleaks 09:22 - #23 OpenCore-Legacy-Patcher 09:45 - Outro & Key Poin Penting ━━━━━━━━━━━━━━━━━━━━━━━ 23 REPOSITORI YANG SEDANG TREN HARI INI: ━━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Summer2027-Internships (⭐ 48,2 ribu • +21 hari ini • Python) Lowongan magang musim panas 2027 di bidang rekayasa perangkat lunak, ilmu data, AI, kuantitatif, manajemen produk, dan perangkat keras. Diperbarui setiap hari oleh Simplify dan Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208,9 ribu • +161 hari ini • TypeScript) Platform otomatisasi alur kerja fair-code dengan kemampuan AI asli. Gabungkan pembuatan visual dengan kode kustom, hosting sendiri atau cloud, 400+ integrasi. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12.9k • +10 hari ini • Python) Platform Konteks untuk Tumpukan Data dan AI Anda 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51.2k • +76 hari ini • TypeScript) 🆙 Upscayl - Pengoptimal Gambar AI Gratis dan Sumber Terbuka #1 untuk Linux, MacOS, dan Windows. 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2k • +55 hari ini • HTML) Daftar penawaran SaaS, PaaS, dan IaaS yang memiliki tingkatan gratis yang menarik bagi devops dan infradev 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 hari ini • Tidak diketahui) Daftar pilihan pekerjaan dan sumber daya jarak jauh yang luar biasa. Terinspirasi oleh vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 hari ini • Jupyter Notebook) 10 Minggu, 20 Pelajaran, Ilmu Data untuk Semua! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140.1k • +84 hari ini • C) Microsoft PowerToys adalah kumpulan utilitas yang meningkatkan produktivitas dan kustomisasi di Windows 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103.2k • +41 hari ini • Skrip Vim) Vim-fork yang berfokus pada ekstensibilitas dan kegunaan 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58.7k • +74 hari ini • C#) Sistem Media Perangkat Lunak Gratis - Backend Server & API 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52.7k • +23 hari ini • Python) LlamaIndex adalah platform pemrosesan dokumen untuk AI 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9.8k • +14 hari ini • Go) Alat dan pustaka CLI untuk menghasilkan Daftar Material Perangkat Lunak dari citra kontainer dan sistem file 🔗 anchore/syft #13 microsoft/playwright (⭐ 98.7k • +90 hari ini • TypeScript) Playwright adalah kerangka kerja untuk Pengujian dan Otomatisasi Web. Ini memungkinkan pengujian Chromium, Firefox, dan WebKit dengan satu API. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61.6k • +64 hari ini • TypeScript) 🔥🔥🔥 Alternatif Jira, Linear, Monday, dan ClickUp sumber terbuka. Plane adalah platform manajemen proyek modern untuk mengelola tugas, sprint, dokumen, dan triase. 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23.5k • +17 hari ini • C) Pencarian kesamaan vektor sumber terbuka untuk Postgres 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━━ Berlangganan @devrepos untuk repositori GitHub yang sedang tren setiap hari, rangkuman sumber terbuka, dan berita pengembang. Video baru setiap hari yang membahas perangkat lunak sumber terbuka terbaik dan proyek-proyek yang sedang tren di GitHub. [it] Lo stack definitivo per sviluppatori: 23 repository GitHub di tendenza | 28/10/2026 | Dev Repos D... Italiano: cutt.ly 🔥 Nessuno ti ha parlato di questo nuovo repository di IA (Tirocini estivi 2027) Rimani aggiornato sull'ecosistema open source con questa selezione accurata di repository GitHub di tendenza. Da strumenti di sviluppo innovativi a framework rivoluzionari, questi sono i progetti che stanno facendo scalpore nella comunità del software in questo momento. 28 ottobre 2026 Contenuto del video: - I 23 repository GitHub più popolari, classificati in base alle stelle guadagnate oggi - Approfondimenti per sviluppatori e panoramiche dei progetti per ogni repository presentato - Guida interattiva con narrazione AI per ogni progetto open source - Link diretti a tutti i repository qui sotto per un facile accesso ⏱️ INDICE DEI CONTENUTI (Capitoli di YouTube): 00:00 - Introduzione: Strumenti di grande impatto di oggi 00:09 - Panoramica della classifica dei più popolari 00:25 - #1 Summer2027-Internships 00:54 - #2 n8n 01:24 - #3 datahub 01:45 - #4 upscayl 02:08 - #5 free-for-dev 02:33 - #6 awesome-remote-job 02:59 - #7 Data-Science-For-Beginners 03:27 - #8 PowerToys 03:50 - #9 neovim 04:10 - #10 jellyfin 04:33 - #11 llama_index 04:56 - #12 syft 05:18 - #13 playwright 05:46 - #14 plane 06:09 - #15 pgvector 06:28 - #16 awesome 06:59 - #17 runner-images 07:19 - #18 rustdesk 07:43 - #19 lazygit 08:05 - #20 transformers 08:31 - #21 directus 09:02 - #22 gitleaks 09:22 - #23 OpenCore-Legacy-Patcher 09:45 - Outro e Key Punti chiave ━━━━━━━━━━━━━━━━━━━━━━━━ I 23 REPOSITORY PIÙ DI TENDENZA DI OGGI: ━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Summer2027-Internships (⭐ 48.2k • +21 oggi • Python) Offerte di stage per l'estate 2027 in ingegneria del software, data science, IA, analisi quantitativa, gestione del prodotto e hardware. Aggiornato quotidianamente da Simplify e Pitt CSC. #1 SimplifyJobs/Summer2027-Internships (⭐ 48.2k • +21 oggi • Python) Offerte di stage per l'estate 2027 in ingegneria del software, data science, IA, analisi quantitativa, gestione del prodotto e hardware. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208.9k • +161 oggi • TypeScript) Piattaforma di automazione del flusso di lavoro con codice equo e funzionalità native di IA. Combina la creazione visuale con codice personalizzato, self-hosting o cloud, oltre 400 integrazioni. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12.9k • +10 oggi • Python) La piattaforma di contesto per il tuo stack di dati e IA 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51.2k • +76 oggi • TypeScript) 🆙 Upscayl - Il miglior strumento gratuito e open source per l'upscaling di immagini basato sull'IA per Linux, MacOS e Windows. 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2k • +55 oggi • HTML) Un elenco di offerte SaaS, PaaS e IaaS con piani gratuiti di interesse per DevOps e InfraDev 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 oggi • Sconosciuto) Un elenco curato di fantastiche offerte di lavoro da remoto e risorse. Ispirato da vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 oggi • Jupyter Notebook) 10 settimane, 20 lezioni, Data Science per tutti! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140.1k • +84 oggi • C) Microsoft PowerToys è una raccolta di utilità che potenziano la produttività e la personalizzazione su Windows 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103.2k • +41 oggi • Vim Script) Fork di Vim focalizzato su estensibilità e usabilità 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58.7k • +74 oggi • C#) Il sistema multimediale software libero - Backend server e API 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52.7k • +23 oggi • Python) LlamaIndex è la piattaforma di elaborazione documenti per l'IA 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9.8k • +14 oggi • Go) Strumento e libreria CLI per la generazione di una distinta base software da immagini container e filesystem 🔗 anchore/syft #13 microsoft/playwright (⭐ 98.7k • +90 oggi • TypeScript) Playwright è un framework per il test e l'automazione web. Consente di testare Chromium, Firefox e WebKit con un'unica API. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61.6k • +64 oggi • TypeScript) 🔥🔥🔥 Alternativa open source a Jira, Linear, Monday e ClickUp. Plane è una moderna piattaforma di gestione progetti per gestire attività, sprint, documentazione e priorità. #14 makeplane/plane (⭐ 61.6k • +64 oggi • TypeScript) 🔥🔥🔥 Un'alternativa open source a Jira, Linear, Monday e ClickUp. Plane è una moderna piattaforma di gestione progetti per gestire attività, sprint, documentazione e priorità. #14 makeplane/plane (⭐ 61.6k • +64 oggi • TypeScript) 🔥🔥🔥 Un'alternativa open source a Jira, Linear, M... [iw] הסטאק האולטימטיבי למפתחים: 23 פרויקטי GitHub חמים | 28/10/2026 | Dev Repos Daily cutt.ly 🔥 אף אחד לא סיפר לכם על מאגר הבינה המלאכותית החדש הזה (קיץ 2027 - התמחויות) הישארו מעודכנים במערכת האקולוגית של קוד פתוח עם מבחר נבחר זה של מאגרי GitHub טרנדיים. מכלי פיתוח חדשניים ועד מסגרות פורצות דרך, אלו הפרויקטים שעושים גלים בקהילת התוכנה כרגע. 28 באוקטובר, 2026 מה יש בסרטון הזה: - 23 מאגרי GitHub הטרנדיים ביותר מדורגים לפי כוכבים שנצברו היום - תובנות מפתחים וסקירות פרויקטים עבור כל מאגר מומלץ - סיור מקיף על כל פרויקט קוד פתוח באמצעות בינה מלאכותית - קישורים ישירים לכל המאגרים למטה לגישה נוחה ⏱️ חותמות זמן (פרקי YouTube): 00:00 - מבוא: הכלים בעלי ההשפעה הגבוהה של היום 00:09 - סקירת טבלת המובילים הטרנדיים 00:25 - #1 קיץ 2027 - התמחויות 00:54 - #2 n8n 01:24 - #3 datahub 01:45 - #4 upscayl 02:08 - #5 free-for-dev 02:33 - #6 awesome-remote-job 02:59 - #7 Data-Science-For-Beginners 03:27 - #8 PowerToys 03:50 - #9 neovim 04:10 - #10 jellyfin 04:33 - #11 llama_index 04:56 - #12 syft 05:18 - #13 playwright 05:46 - #14 plane 06:09 - #15 pgvector 06:28 - #16 awesome 06:59 - #17 runner-images 07:19 - #18 rustdesk 07:43 - #19 lazygit 08:05 - #20 transformers 08:31 - #21 directus 09:02 - #22 gitleaks 09:22 - #23 OpenCore-Legacy-Patcher 09:45 - סיום וסולם נקודות חשובות ━━━━━━━━━━━━━━━━━━━━━━━ 23 המאגרים הטרנדיים ביותר של היום: ━━━━━━━━━━━━━━━━━━━━━━━ #1 SimplifyJobs/Kitchen2027-Internships (⭐ 48.2k • +21 היום • Python) פרסומי התמחויות בהנדסת תוכנה, מדעי נתונים, בינה מלאכותית, כימות, ניהול מוצר וחומרה בקיץ 2027. מתעדכנים מדי יום על ידי Simplify ו-Pitt CSC. 🔗 SimplifyJobs/Summer2027-Internships #2 n8n-io/n8n (⭐ 208.9k • +161 היום • TypeScript) פלטפורמת אוטומציה של זרימת עבודה בקוד הוגן עם יכולות בינה מלאכותית מקוריות. שלב בנייה ויזואלית עם קוד מותאם אישית, אירוח עצמי או ענן, 400+ אינטגרציות. 🔗 n8n-io/n8n #3 datahub-project/datahub (⭐ 12.9k • +10 היום • Python) פלטפורמת ההקשר עבור מחסנית הנתונים והבינה המלאכותית שלך 🔗 datahub-project/datahub #4 upscayl/upscayl (⭐ 51.2k • +76 היום • TypeScript) 🆙 Upscayl - #1 משדרג תמונות בינה מלאכותית חינמי וקוד פתוח עבור לינוקס, MacOS ו-Windows. 🔗 upscayl/upscayl #5 ripienaar/free-for-dev (⭐ 140.2k • +55 היום • HTML) רשימה של הצעות SaaS, PaaS ו-IaaS שיש להן שכבות חינמיות שמעניינות מפתחי פיתוח ופיתוח אינפרא-אדום 🔗 ripienaar/free-for-dev #6 lukasz-madon/awesome-remote-job (⭐ 50k • +99 היום • לא ידוע) רשימה אוצרת של עבודות ומשאבים מדהימים מרחוק. בהשראת vinta/awesome-python 🔗 lukasz-madon/awesome-remote-job #7 microsoft/Data-Science-For-Beginners (⭐ 37.8k • +47 היום • Jupyter Notebook) 10 שבועות, 20 שיעורים, מדעי נתונים לכולם! 🔗 microsoft/Data-Science-For-Beginners #8 microsoft/PowerToys (⭐ 140.1k • +84 היום • C) Microsoft PowerToys הוא אוסף של כלי עזר שמשפרים את הפרודוקטיביות וההתאמה האישית ב-Windows 🔗 microsoft/PowerToys #9 neovim/neovim (⭐ 103.2k • +41 היום • סקריפט Vim) Vim-fork המתמקד בהרחבה ושימושיות 🔗 neovim/neovim #10 jellyfin/jellyfin (⭐ 58.7k • +74 היום • C#) מערכת המדיה של תוכנה חופשית - שרת Backend ו-API 🔗 jellyfin/jellyfin #11 run-llama/llama_index (⭐ 52.7k • +23 היום • Python) LlamaIndex היא פלטפורמת עיבוד מסמכים עבור בינה מלאכותית 🔗 run-llama/llama_index #12 anchore/syft (⭐ 9.8k • +14 היום • Go) כלי וספרייה של ממשק שורת פקודה (CLI) ליצירת רשימת חומרים של תוכנה מתמונות של מכולות ומערכות קבצים 🔗 anchore/syft #13 microsoft/playwright (⭐ 98.7k • +90 היום • TypeScript) Playwright היא מסגרת לבדיקות אינטרנט ואוטומציה. היא מאפשרת בדיקת Chromium, Firefox ו-WebKit עם API יחיד. 🔗 microsoft/playwright #14 makeplane/plane (⭐ 61.6k • +64 היום • TypeScript) 🔥🔥🔥 אלטרנטיבה בקוד פתוח ל-Jira, Linear, Monday ו-ClickUp. Plane היא פלטפורמת ניהול פרויקטים מודרנית לניהול משימות, ספרינטים, מסמכים וטראז'. 🔗 makeplane/plane #15 pgvector/pgvector (⭐ 23.5k • +17 היום • C) חיפוש דמיון וקטורי בקוד פתוח עבור Postgres 🔗 pgvector/pgvector ━━━━━━━━━━━━━━━━━━━━━━━━ הירשמו ל-@devrepos לקבלת מאגרי GitHub יומיים פופולריים, סיכומים בקוד פתוח וחדשות מפתחים. סרטונים חדשים מדי יום המכסים את תוכנות הקוד הפתוח הטובות ביותר ופרויקטים פופולריים ב-GitHub. [ja] 究極の開発者スタック:GitHubでトレンドのレポジトリ23選 | 2026年10月28日 | 開発者レポジトリ・デイリー cutt.ly 🔥 誰も教えてくれなかった、注目のAIリポジトリ(2027年夏期インターンシップ) 厳選された話題のGitHubリポジトリで、オープンソースエコシステムの最新情報を常に把握しましょう。革新的な開発ツールから画期的なフレームワークまで、ソフトウェアコミュニティで今まさに注目を集めているプロジェクトをご紹介します。 2026年10月28日 この動画の内容: - 本日獲得したスター数でランキングされた、GitHubで話題のリポジトリ上位23件 - 各リポジトリの開発者向け解説とプロジェクト概要 - AIによるナレーション付き、各オープンソースプロジェクトの解説 - すべてのリポジトリへの直接リンク(下記参照) ⏱️ タイムスタンプ(YouTubeチャプター): 00:00 - はじめに:今日の注目ツール 00:09 - トレンドランキング概要 00:25 - #1 Summer2027-Internships 00:54 - #2 n8n 01:24 - #3 datahub 01:45 - #4 upscayl 02:08 - #5 free-for-dev 02:33 - #6 awesome-remote-job 02:59 - #7 Data-Science-For-Beginners 03:27 - #8 PowerToys 03:50 - #9 neovim 04:10 - #10 jellyfin 04:33 - #11 llama_index 04:56 - #12 syft 05:18 - #13 playwright 05:46 - #14 plane 06:09 - #15 pgvector 06:28 - #16 awe
已有 Postgres 的项目做语义检索,可看看开源 pgvector:向量与业务数据放在同一库,支持 SQL 过滤和关联查询。需安装扩展,另选嵌入模型生成向量。先用精确检索作基准;HNSW 等近似索引能提速,但会牺牲召回,带过滤条件时尤其要检查结果是否足量。 pgvector/pgvector
From Rows to Vectors: pgvector inside Postgres --- title: "From Rows to Vectors: pgvector inside Postgres" published: true description: "What a vector database does, how HNSW and IVFFlat work, and the traps of running pgvector inside the Postgres you already run." tags: postgres, pgvector, node, ai --- Say your product needs search that understands meaning. A user types "the tax due when you sell shares at a profit" and expects the page on capital gains tax, even though none of those words appears in its title. The usual next step is a new piece of infrastructure: Pinecone, Qdrant, Milvus or Weaviate, with its own bill, its own SLA and a sync job to keep it in step with your real data. There is another option: keep the embeddings in pgvector, inside the PostgreSQL database you already run. This article explains what a vector database does, how its indexes work, and what to watch for when you run one inside Postgres, including the traps that are easy to ship without noticing. --- Two kinds of questions A relational database answers "which rows are equal to this?" SELECT * FROM orders WHERE customer_id = 42; The answer is exact. A row matches, or it does not. A vector database answers "which rows are like this?" SELECT id, body FROM documents ORDER BY embedding <=> $1 LIMIT 5; The answer is a ranking. Every row sits some distance away from the query, and you ask for the closest few. Everything else in this article follows from that one change of contract. | | Relational database | Vector database | | --- | --- | --- | | Stores | rows of typed columns | vectors, plus metadata | | Asks | equal, range, join | the k nearest to a query vector | | Index | B-tree, hash: exact lookups | HNSW, IVF: approximate search | | Answer | an exact set of rows | a ranked list that may miss a few | | Built for | transactions, constraints, joins | similarity over millions of vectors | | Examples | PostgreSQL, MySQL | Pinecone, Qdrant, Milvus, Weaviate | pgvector puts the right-hand column inside the left-hand one. --- From meaning to numbers An embedding model turns a piece of content into a fixed-length list of numbers. It is trained so that similar meanings produce similar numbers. OpenAI's text-embedding-3-small returns 1,536 numbers by default, and text-embedding-3-large returns 3,072. Both accept a dimensions parameter to return fewer (OpenAI embeddings guide). Two properties matter in practice: - Fixed length. ** A single word and a full page produce the same number of dimensions. - One model for both sides. ** Stored rows and incoming queries must go through the same model, with the same settings. Swap the model and every stored vector needs re-embedding. Meaning as a place Picture those numbers as coordinates. Real embeddings have 1,536 axes, but two are enough to get the idea. "cat", "dog" and "puppy" land close together. "pizza", "pasta" and "bread" form their own cluster. "capital gains tax", "CGT" and "tax on a share sale" sit in a third. Search becomes geometry. Embed the query with the same model, then ask for its nearest neighbours. A query for "kitten" finds "cat" and "puppy", although "kitten" is a different word from both. No keyword matching is involved. "Near" needs a definition pgvector ships several distance operators (pgvector README, Querying): | Operator | Distance | What it measures | | --- | --- | --- | | <-> | L2 (Euclidean) | the straight-line gap between the two points | | <=> | cosine | the angle between the vectors; length is ignored | | <#> | negative inner product | angle and length, negated so that smaller means closer | | <+> | L1 (taxicab) | the sum of the per-axis differences | | <~>, <%> | Hamming, Jaccard | for binary (bit) vectors | > Note: <#> returns the negative inner product because Postgres only supports ascending-order index scans on operators (pgvector README, Getting Started). Multiply by -1 if you want the real value. The pgvector README states that OpenAI embeddings are normalised to length 1, and recommends inner product for best performance on normalised vectors (pgvector README, Exact Search). For unit-length vectors, inner product ranks results in the same order as cosine. --- Why a B-tree can't help A B-tree handles equality and range queries on data that can be sorted into an order (PostgreSQL docs, Index Types). WHERE id = 42 takes a few hops down the tree and lands on the row. "Nearest to this vector" has no fixed order. Every query has its own centre, so nothing can be sorted in advance. Without an approximate index, pgvector performs exact nearest neighbour search: it compares the query against every row (pgvector README, Indexing). The cost adds up quickly. Take one million rows of 1,536-dimensional vectors: - 1.5 billion multiply-adds per query (1,000,000 × 1,536). - About 6.2 GB read per query. ** pgvector stores each vector in 4 × dimensions + 8 bytes, so 6,152 bytes per row (pgvector README, Vector Type). Exact search returns perfect recall, and its cost grows in a straight line with the table. Approximate nearest neighbours Vector indexes give up a little accuracy to stop reading everything. The measure for that accuracy is recall: the share of the true k nearest neighbours that actually come back. Two things follow: - Recall is a dial. ** Each index type has a query-time setting that trades speed for recall. You choose where to sit on the curve. - Adding an index can change your results. The pgvector README says it directly: you will see different results for queries after adding an approximate index (pgvector README, Indexing). A test that passed against a sequential scan can fail the day the index ships. --- IVFFlat: cluster first, then search a few clusters IVFFlat divides the vectors into lists, each grouped around a centroid, and a query searches only the lists closest to it. The number of lists it searches is probes, and the default is 1 (pgvector README, IVFFlat). The lists come from k-means over the rows present at build time; the index build reports a performing k-means phase. The weakness is at the borders. If the true nearest neighbour sits just over the edge of a neighbouring list, a query with probes = 1 never looks there. The README gives these starting points: - lists = rows / 1000 for up to 1M rows, and sqrt(rows) above that. - probes = sqrt(lists). - Create the index after the table has some data. CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); SET ivfflat.probes = 10; The README's troubleshooting section names the symptom too: an IVFFlat index created with too little data for its number of lists returns fewer results (pgvector README, Troubleshooting). An easy way to hit this. ** Indexes usually arrive through migrations, and migrations usually run before any data exists. An IVFFlat index created that way builds its lists from an empty table. Leave probes at its default, and every query searches one list out of 100. The fix is a REINDEX once the data is loaded, and an explicit SET ivfflat.probes per query. Better still, use HNSW, which has no training step. --- HNSW: a layered graph HNSW (Hierarchical Navigable Small World) comes from a paper by Malkov and Yashunin (arXiv 1603.09320). It builds a graph in layers. The top layer has few nodes and long links; each layer below has more nodes and shorter links, down to layer 0, which holds every vector. A search starts at the top, hops to whichever neighbour is closer to the query, drops a layer, and repeats. Its settings and their defaults (pgvector README, HNSW): - m = 16: the maximum number of connections per layer. - ef_construction = 64: the size of the candidate list while building. - hnsw.ef_search = 40: the size of the candidate list per query. This is the recall dial. HNSW has no training step, so you can create it on an empty table. CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops); SET hnsw.ef_search = 100; Builds are much faster when the graph fits in maintenance_work_mem, and Postgres prints a notice when it no longer does (pgvector README, Index Build Time). --- Choosing between them All rows below come from the pgvector README. | | HNSW | IVFFlat | | --- | --- | --- | | Structure | multilayer graph | lists around centroids | | Training | none: can build on an empty table | k-means: build after loading | | Build | slower, more memory | faster, less memory | | Speed vs recall | better | lower | | Query dial | hnsw.ef_search, default 40 | ivfflat.probes, default 1 | | Build dials | m = 16, ef_construction = 64 | lists | My default is HNSW, unless build time or memory is the constraint. It gives a better speed-recall trade-off, and it removes the empty-table trap entirely. --- pgvector: a vector database inside Postgres pgvector is an open-source Postgres extension; the README's install instructions reference version 0.8.7 at the time of writing (pgvector README, Installation). It adds vector types, distance operators and the two index types above. Everything you already rely on stays: ACID transactions, joins, point-in-time recovery, replication and the query planner. On AWS, Aurora PostgreSQL supports it (AWS announcement: pgvector 0.8.0 on Aurora PostgreSQL). CREATE EXTENSION vector; --- Types and limits One 1,536-dimension embedding takes this much space in each type. Storage formulas and index limits come from the pgvector README reference and its HNSW section. | Type | Element | Bytes for 1,536 dims | Index up to | | --- | --- | --- | --- | | vector | float32 | 6,152 (4 × d + 8) | 2,000 dims | | halfvec | float16 | 3,080 (2 × d + 8) | 4,000 dims | | bit | 1 bit, lossy | 200 (d ÷ 8 + 8) | 64,000 dims | | sparsevec | non-zero elements only | 8 × non-zero + 16 | 1,000 non-zero, HNSW only | Vectors can store up to 16,000 dimensions; only indexing is limited. A 3,072-dimension model such as text-embedding-3-large cannot be indexed as vector, but it can be indexed as halfvec (pgvector README FAQ). > Note: bit keeps only one bit per dimension. Use it as a fast first pass and re-rank with the full vector (see scaling below). A table, an index, a query CREATE TABLE documents ( id bigserial PRIMARY KEY, body text NOT NULL, embedding vector(1536) NOT NULL ); CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops); -- the five nearest to a query vector SET hnsw.ef_search = 100; SELECT id, body FROM documents ORDER BY embedding <=> $1 LIMIT 5; Four details that cost people time: - The dimension is part of the column type. A vector(1536) column holds 1,536-dimensional vectors; to mix dimensions, you need the unsized vector type (pgvector README FAQ). - The index serves one distance function. The README says to add an index for each distance function you want to use (pgvector README, HNSW). An index built with vector_cosine_ops speeds up <=> only. - hnsw.ef_search is per session. Use SET LOCAL inside a transaction to change it for one query (pgvector README, Query Options). - The index needs both ORDER BY and LIMIT, and the ORDER BY must be the distance operator itself in ascending order. ORDER BY 1 - (embedding <=> $1) DESC skips the index (pgvector README, Troubleshooting). Why cosine here, after I said inner product is fastest? For unit-length vectors, the two give identical rankings, and cosine stays correct if a future model does not normalise its output. I chose safety over a small speed gain. The same query from Node.js The pgvector npm package supports node-postgres, Knex.js, Kysely, Prisma, Drizzle ORM and several other libraries (pgvector-node README). npm install pgvector pg openai import OpenAI from 'openai' import pg from 'pg' import pgvector from 'pgvector/pg' const question = 'the tax due when you sell shares at a profit' const client = new pg.Client() await client.connect() await pgvector.registerTypes(client) // reads OPENAI_API_KEY from the environment const { data } = await new OpenAI().embeddings.create({ model: 'text-embedding-3-small', input: question, }) const { rows } = await client.query( `SELECT id, body FROM documents ORDER BY embedding <=> $1 LIMIT 5`, [pgvector.toSql(data[0].embedding)], ) Where each part comes from: - registerTypes and toSql follow the pgvector-node README, node-postgres section. With a pool, call registerTypes in the pool's onConnect hook. - registerType (singular) is deprecated since pgvector-node 0.3.0 (pgvector-node README, Upgrading). - new OpenAI() reads OPENAI_API_KEY from the environment (openai-node README). - The response's data array holds one item per input, each with an embedding field (OpenAI API reference, Create embeddings). --- Production trap 1: WHERE runs after the index scan This one bites quietly. With an approximate index, filtering is applied after the index is scanned. The pgvector README gives the numbers: if a condition matches 10% of rows, HNSW with the default ef_search of 40 leaves only about 4 matching rows on average (pgvector README, Filtering). Ask for 10, and you get about 4. No error, no warning: just fewer results. -- asks for 10, typically gets about 4 back once an HNSW index exists SELECT id, body FROM documents WHERE course_id = 123 ORDER BY embedding <=> $1 LIMIT 10; Since pgvector 0.8.0, iterative index scans fix this (pgvector CHANGELOG). When enabled, the scan keeps reading the index until enough results are found, or until it reaches hnsw.max_scan_tuples (default 20,000) or ivfflat.max_probes (pgvector README, Iterative Index Scans). SET hnsw.iterative_scan = strict_order; -- or, trading exact ordering for recall: SET hnsw.iterative_scan = relaxed_order; -- IVFFlat supports relaxed ordering only SET ivfflat.iterative_scan = relaxed_order; Other options from the README: an index on the filter column for conditions that match a low percentage of rows, a partial index when you filter by a few distinct values, and partitioning when you filter by many (pgvector README, Filtering). For tenant isolation, it recommends list partitioning or separate tables (pgvector README, Multitenancy). Why this one survives code review. ** A filtered similarity query on a table with no vector index returns exact results, because Postgres scans everything. The day someone adds an index for speed, the same query starts returning fewer rows, with no error. A test that runs against a small, unindexed table will not catch it. If you filter, decide on iterative scans before you add the index. --- Production trap 2: keywords and meaning need each other Vector search misses exact identifiers. Search for a course code or a regulation number and the embedding treats it as noise. Full-text search has the opposite gap: it misses paraphrases. Hybrid search runs both and merges the results. The pgvector README suggests combining it with Postgres full-text search, using Reciprocal Rank Fusion or a cross-encoder to merge (pgvector README, Hybrid Search). The merge is the hard part, because the scores live on different scales. Cosine distance and ts_rank cannot be added together. Reciprocal Rank Fusion (RRF) sidesteps that by combining positions instead of scores. The constant k smooths the score so that a first place does not dominate: score(doc) = Σ 1 / (k + rank) With k = 50, the default rrf_k in Supabase's hybrid search guide: | Doc | Full-text rank | Vector rank | RRF score | | --- | --- | --- | --- | | A | 2 | 1 | 1/52 + 1/51 = 0.0388 | | B | 1 | 3 | 1/51 + 1/53 = 0.0385 | | C | not ranked | 2 | 1/52 = 0.0192 | | D | 3 | not ranked | 1/53 = 0.0189 | Documents A and B appear in both lists, so they rise to the top. A document that only one method found still scores, just lower. In Postgres, both halves live in the same table. Keep a tsvector column next to the vector column, run the two ranked queries as CTEs, and join them on the document ID. Supabase's guide shows a complete SQL function built this way. --- Production trap 3: scaling before you buy The usual argument for a dedicated vector store is scale. Before taking on another service, pull the Postgres levers first. The README lists them (pgvector README, Scaling); the order is mine: 1. halfvec columns. Half the bytes per vector, so a smaller working set. 2. Binary quantization for the index, then re-rank the shortlist at full precision. 3. maintenance_work_mem large enough for HNSW to build in memory. 4. A bigger instance: more memory, CPU and storage. 5. Read replicas, then Citus or PgDog to shard. The binary quantisation pattern, adapted from the README: CREATE INDEX ON documents USING hnsw ((binary_quantize(embedding)::bit(1536)) bit_hamming_ops); SELECT * FROM ( SELECT * FROM documents ORDER BY binary_quantize(embedding)::bit(1536) <~> binary_quantize($1) LIMIT 20 ) shortlist ORDER BY embedding <=> $1 LIMIT 5; A dedicated store earns its place when those levers are pulled, and your recall or latency targets still miss, or when vector traffic has to scale independently of the transactional database. I looked for an independent benchmark that names the size where Postgres stops being enough, and did not find one. Measure recall and latency on your own data before deciding. The README shows how: compare approximate results with exact search by running the query with SET LOCAL enable_indexscan = off (pgvector README, Monitoring). --- When you don't need an index at all Not every vector table needs an approximate index. Two common shapes: - Few-shot examples for an LLM. ** You pick the most similar past examples to put in a prompt. These tables are often small, so exact search with no index is fast enough, and it gives perfect recall for free. - A document library for retrieval. Uploaded documents are chunked and embedded, with a full-text column beside each vector, ready for hybrid search. This is the shape that grows, and where the index decisions above start to matter. Start without an index, measure latency, and add one when the numbers ask for it. When you do, revisit every filtered query first. --- Three things to take home 1. A vector database answers "like this". Embeddings turn meaning into distance; nearest neighbours turn distance into results. 2. Approximate means a dial. ef_search and probes trade speed for recall. Treat the defaults as a starting point and tune from there. 3. Start in Postgres; earn the next database. pgvector keeps vectors beside the rows they describe, in a system you already back up, monitor and understand. Measure recall and latency before adding a service to run. And you? Did you start with a dedicated vector store, or keep everything in Postgres? If you have hit a recall or latency wall with pgvector, I would like to know the table size and the setting that broke it. Drop a comment if you have questions. Bruno Souza, Software Engineer --- Sources - pgvector README: types, operators, HNSW, IVFFlat, filtering, iterative scans, hybrid search, scaling, monitoring - pgvector CHANGELOG: 0.7.0 types, 0.8.0 iterative scans - pgvector-node README: Node.js usage, supported libraries, 0.3.0 upgrade notes - OpenAI embeddings guide: model dimensions and the dimensions parameter - OpenAI API reference, Create embeddings: response shape - openai-node README: client construction and API key - PostgreSQL docs, Index Types: what a B-tree handles - Malkov and Yashunin, Efficient and robust approximate nearest neighbour search using Hierarchical Navigable Small World graphs - Supabase docs, hybrid search: RRF with rrf_k = 50 - AWS: pgvector 0.8.0 support in Aurora PostgreSQL Facts checked on 20 October 2026.
はじめてのインデータベースAI~ベクトル検索・RAGからAIエージェントまで~ はじめに この記事は 2026/10/21 の Oracle AI Jam Session #41 はじめてのインデータベースAI~ベクトル検索・RAGからAIエージェントまで~ にてご紹介させていただいたものです。 <iframe width="560" height="315" src="youtube.com" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> 生成AIを業務で活用するには、社内ナレッジや業務データを安全かつ適切に検索し、回答やアクションにつなげる仕組みが必要です。本記事では、データベースの中でベクトル検索によるセマンティック・サーチ、埋め込みモデルによるベクトル生成、検索拡張生成、自然言語によるデータ照会、AIエージェントを実現する「インデータベースAI」の考え方を、初学者にも分かる全体像とコード例・デモを通じて紹介します。初学者の方だけでなくデータベースの専門家としてのスキルやキャリアを活かして AI 活用への取り組みをお考えのベテラン・エンジニアの方にもお役に立てる内容を目指しています。 oracle-code-tokyo-dev.connpass.com ご紹介するコードや環境構築手順は GitHubリポジトリで公開しています。ぜひ、実際に動かして体験してみてください。 kutsushitaneko/orajam41-in-database-ai-demo 「管理画面が開きません!どうしたらいいですか?見に来てくれますか?」 !サーバールームの電話対応 「保守登録番号DEV001のラックサーバーで、管理画面が開かない。最初に何を確認すればよいですか?現地保守を頼めますか?」 !AIアシスタントと保守確認-2.png こんな問い合わせに答えるには、製品のマニュアルだけでなく、そのサーバーの保守契約も必要ですね。 !AIでつなぐ保守対応-3.png 一般的な対処法を知っているAIでも、社内の最新マニュアルや顧客の契約を参照しなければ、この問い合わせへの答えを出すことはできません。つまり、AI を本格的に業務利用するためには AI に 業務データを活用させてあげることが必要です。 !AI の業務利用で大切なこと 一方で、AI、特に、人に代わって自律的に仕事を進めてくれる AI エージェントに大切な業務データへのアクセスを許可することにはリスクが伴います。 !AI の業務利用で心配なこと そこで、業務データを管理している場所で、AIに必要な検索や処理を実行するという考え方が出てきます。 !データのあるところへAIを持っていく この記事では、 「データのあるところへAIを持っていく」 という考え方を、サーバー機器メーカーの保守問い合わせ窓口の顧客対応を例に見ていきます。意味的な類似性に基づいて文書を探すところから始め、根拠付きの回答、契約の照会、複数の処理を使うAIエージェントへと進みます。 この記事の読者想定は、SELECT・WHERE・JOINなどのデータベースの基礎を知っている方です。AIの予備知識は不要です。実装例にはAutonomous AI Database 26aiを使いますが、検索・生成・業務処理の役割分担は他の構成にも応用できると思います。 この記事は以下のような構成になっています。 | 章 | 内容 | デモ | |---|---|---| | 第1章 | 文書の意味検索と、業務データの照会を組み合わせる | — | | 第2章 | 埋め込みモデルをDB内へ持ち込み、SQLでベクトルを作る | ベクトル基礎 | | 第3章 | チケットの顧客と機種を絞って、ベクトル検索する | A:意味検索 | | 第4章 | 検索した文書を根拠に、RAGで回答する | B:RAG | | 第5章 | NL2SQL で契約情報を照会する | C:NL2SQL | | 第6章 | 文書検索と契約照会をAgentのツールにする | D:Agent | 記事中の実行用コードは動作確認済みです。手元で再現する場合は、先に末尾のAppendixでユーザー作成から環境を準備してください。コードとデータ生成器はこちらです。 1. 文書の意味検索と業務データの照会を組み合わせる 一つの問い合わせに性質の異なる二つの問いがある この記事では、メーカーの保守担当者がラックサーバーの問い合わせに対応する場面を考えていきます。 顧客は保守登録番号DEV001のサーバーについて、「管理画面が開かない。確認手順を知りたい。現地保守も頼めるか」と問い合わせてきています。 :::note warn 登場する企業・機種・保守手順は、すべて本記事用の架空のものです。 ::: - 「何を確認すればよいか」 は、症状に関連するマニュアルや保守手順 を探す問いです。 - 一方、「現地保守を頼めるか」 は、そのサーバーの契約状態・有効期間・サービス範囲 を確かめる問いです。同じ製品機種でも、契約によって対応できる内容は異なるという想定です。 flowchart LR Q["管理画面が開かない。<br>どうしたらいい?<br>現地保守を頼める?"] Q --> P["症状に合う手順は?"] Q --> C["この1台の契約で対応できる?"] P --> D["マニュアルなどの文書で<br>意味の近い記述を検索"] C --> R["データベースの契約表で<br>契約状態・期間・範囲を照合"] D --> A["根拠のある確認手順と<br>対応案を提示"] R --> A - 上段は、マニュアルや保守手順書といった 非構造化データの意味検索(セマンティックサーチ) が適した問い - 下段は、契約表(テーブル)のような リレーショナルデータベースの検索 を必要とする問い これから先は、まずは意味検索、次に根拠付きの文章生成、契約情報への自然言語照会、最後にそれらを使うエージェントへと見ていきます。 ベクトル検索は文字の一致だけでは拾えない候補も探してくれる 「管理画面が開かない」や「管理画面が固まった」、「管理画面が応答しない」は、同じ文字列ではありませんが関連する症状です。 「管理画面が開かない」という症状の訴えに対して、「管理画面が固まった」や「管理画面が応答しない」という症状について書かれているドキュメントを見つける必要がありますが、キーワード検索ではこれらのドキュメントを見つけられない可能性があります。 そこで、意味検索(セマンティックサーチ)が必要になります。つまり、意味的に近いドキュメントを見つける検索です。このような検索を実現する技術にベクトル検索があります。 !image.png - 埋め込みモデルという機械学習モデルで、テキストや画像の特徴を反映したベクトル(数値の列)を生成します - ベクトル間の距離が近いもの同士は元のデータの特徴が似ている、距離が遠いものは似ていないということになります !image.png ベクトル検索の処理概要 !文書と質問を同じモデルでベクトル化して比較する - 製品マニュアルなどのドキュメントをベクトルに変換してデータベースへ格納 - 「管理画面が開かないけど、どうしたらいい?」などの質問文も 同じ埋め込みモデル でベクトルへ変換 - データベースのドキュメント・ベクトルの中で質問文のベクトルに距離的に近いものを探します :::note ベクトル間の距離指標 - 距離の指標には、コサインやユークリッド距離など様々なものがあります。 - 距離指標は、埋め込みモデルの学習方法や公開されている推奨設定に合わせて選びます。 - 一般的に利用されている埋め込みモデルではコサインが使われていることが多いようです。 ::: :::note warn チャンキング - テキストを埋め込みモデルでベクトル化する際には、1つのベクトルに変換できるテキストの長さには制限があります。 - ドキュメントなどをこの制限内に収まるように分割することを チャンキング と呼び、細分化されたテキストの断片を チャンク と呼びます。 - この記事では、簡略化のため短いドキュメントを用意して、1ドキュメント=1チャンクとしています。 ::: 意味の類似性で探すドキュメントとリレーショナルデータで管理される業務上の契約条件を同じDBで扱う 症状がよく似ていても、別機種の手順や別顧客専用の文書を案内してはいけません。意味の近さに加えて、「誰の問い合わせか」「どの機種か」「公開済みか」といった条件が必要になります。ここで、顧客・サーバー・契約などのリレーショナルデータが役立ちます。 一般的な検索アプリケーションでは、検索画面に「機種」「地域」「公開区分」などの絞り込み項目が用意されています。こうした絞り込みの切り口を、ファセットと呼びます。値ごとの件数を表示し、選んだ属性で候補を絞る使い方が典型です。 ベクトルDBでも、文書に付けたメタデータを使ってフィルタリングできるようになっています。例えばQdrantは、payloadという付加情報のフィルターと、属性値ごとの件数を返すfacetingを提供しています。Qdrantのpayloadとfaceting 製品に関する単純な仕様質問なら、文書のメタデータに対する model=AX-100 のようなフィルタ条件で十分です。一方、今回のシナリオのような「対応中のチケットの顧客が契約しているサーバーの機種」「現在公開中で、その顧客が閲覧できる文書」のような条件は、契約や権限の変更に追随する必要があります。 このような業務データは、リレーショナルデータベースで管理されていることが多いかと思います。ベクトルDBのメタデータによるフィルタリングだけでこれらの条件を判定するには、判定に必要な情報をメタデータやタグとして複製し、契約や権限の変更に合わせて更新する必要があります。 業務表とベクトルが同じリレーショナルデータベースにあれば、検索用に複製したメタデータやタグの更新を待たず、元の表をJOINやEXISTSで参照して条件を表現できます。 | 条件・運用上の課題 | RDB内のベクトル検索で使える仕組み | この記事のコード例とのつながり | |---|---|---| | 製品ドキュメントだけでは顧客や契約の関係が分からない | JOIN・EXISTSで複数の表の関係を条件にする | 顧客、契約、サーバー、文書を同じDBで照会する | | 契約終了や公開取消をすぐ反映したい | 元データを参照するビューとトランザクション | 閲覧用ビューが顧客範囲・公開状態を反映する | | 日付や件数を含む条件が必要 | 日付比較、GROUP BY、HAVINGなどのSQL | 契約の有効期間や機種別の対象数を判定する | | 検索経路ごとにアクセス管理を増やしたくない | DB権限、ビュー、構成に応じた行制御や監査 | SQL検索とPL/SQLツールで同じ閲覧範囲を使う | この利点はOracleだけのものではありません。PostgreSQLのpgvectorもJOINやトランザクションと組み合わせられます。MySQLにも、SQLで埋め込み生成や類似検索を提供するMySQL HeatWaveがあります。pgvector、MySQL HeatWaveのベクトル生成と検索 Oracleでは、リレーショナル表とベクトルに加え、JSONや全文検索、地理空間情報、グラフなども同じデータ基盤で扱えます。業務データの種類ごとに検索用の別システムを増やす前に、既存DBのデータとSQLをどこまで使えるかを考えられます。 :::note こんなことも SQL 1つで実行できます !image.png ::: データを複製すると検索以外の仕事も増える !image.png AIアプリケーションを作るとき、業務DBから文書や契約を取り出し、別の検索基盤へ複製する構成はよく使われます。 この構成には、検索処理を独立して拡張できる利点があります。一方、契約更新をいつ反映するか、削除済み文書をどう消すか、顧客ごとの閲覧範囲をどう同期するか、という仕事も発生します。 例えば、業務DBで契約が解約されたのに、ベクトルDBなど、AIで利用するために複製したデータが昨日のままなら、検索自体が正しくても誤った案内につながります。顧客が契約を解約したり、保守窓口担当者が異動するなど文書の閲覧権限が変更された場合も同様です。必要なのは、似た文章を探す能力だけではありません。 どの時点の情報を、誰の権限で使っているか を制御できる構成です。 Oracleが示す「データのあるところへAIを持っていく」という方向性は、業務データの近くで意味検索や推論を実行し、既存のデータ管理と組み合わせるものです。AI Vector Searchでは、ベクトルを業務表と同じDBに保存し、SQLから統合的に扱うことができます。Oracle AI Vector Search ただし、同じDBに置くだけで鮮度や権限が自動的に正しくなるわけではありません。本文を更新したら対応するベクトルも更新する必要があります。検索に使うビューや実行ユーザーの権限も設計します。DB経験者が行ってきたデータ整合性・権限・運用の設計が、ここでも必要になります。 2. 埋め込みモデルをDB内へ持ち込み、DBの中でベクトルを作る 前章では、文書のベクトルと業務データを同じDBで扱う意義を見ました。次に、そのベクトルを作る埋め込みモデルの配置場所を考えます。 埋め込みモデルは外部サービスに置くか、DB内に置くか ベクトル検索を組み立てるとき、一般的な構成の一つは、外部のクラウドサービスに埋め込みを依頼する方式です。アプリケーションから文書や質問をAPIへ送り、返されたベクトルをDBへ保存したり、検索に使ったりします。例えばOCI Generative AIも、文章をベクトルへ変換するAPIを提供しています。外部サービスでの埋め込み生成 !image.png Oracle AI Database では、埋め込みモデルをデータベースにインポートして、データベースの中でベクトル化する構成を取ることもできます。 !image.png ここで、ちょっと先走りですが、ベクトル検索結果を元に自然文で回答を生成する RAG(検索拡張生成)における埋め込みモデルと回答生成用LLMに渡すデータの範囲を比べてみます。 ベクトルデータベースにデータを投入する際には、 ベクトル化の対象に選んだ文書の全チャンク 、つまり、文書全体を、埋め込みモデルへ順次入力します。一方、RAG回答生成では、検索で取得した少数のチャンクを質問と一緒にLLMへ渡します。RAGの準備と質問時の流れ | 場面 | 埋め込みモデルへ渡すデータ | LLM へ渡すデータ | |---|---|---| | 初回の埋め込み生成 | 検索対象文書の全チャンク | なし | | 文書の追加・改訂 | 追加・変更したチャンク | なし | | 質問の埋め込み生成 | 質問文 | なし | | RAGの回答生成 | なし | 質問と取得した文書抜粋 | つまり、外部の埋め込みAPIを使うと、検索対象の文書をすべて外部へ送ることになります。 埋め込みモデルをデータの近くへ配置する動機はここにあります。文書全体の移動を抑えながら、外部LLMへは回答に必要な箇所を選んで渡せるためです。 データベースによっては、対応する埋め込みモデルを内部へインポートし、SQLから実行できるものがあります。 Oracle AI Databaseでは、対応するONNX形式のモデルをDB内のランタイムで実行します。ONNXは機械学習モデルの標準フォーマットです。DB内での埋め込み生成 | 観点 | 外部の埋め込みサービスを利用 | 対応モデルをDB内へインポート | |---|---|---| | データの移動 | 文書・質問を外部APIへ送信 | 埋め込みのための外部API送信を省ける | | 推論の運用 | サービス側が推論基盤を管理。利用可能なモデルから選ぶ | モデルの取得・変換・ロード・更新を管理する | | 資源と費用 | API利用料・利用上限を考慮。推論負荷をDBから分離できる | DBのCPU・メモリーを使い、他のDB処理との競合を考慮する | | レイテンシー | 推論時間に加え、通信やサービス側の待ち時間がかかる | APIとの往復を省けるが、モデルやDB資源によって推論時間は変わる | DB内実行のメリットは、データの移動を減らし、SQLから埋め込みと検索を扱えることです。その代わり、大きなモデルのメモリー消費や同時実行数もDBの運用として考慮する必要があります。 また、一般にクラウドサービスの埋め込みモデルはGPU 上で稼働していますが、データベースにインポートする場合は CPU で稼働することとなりますので単純に「DB内だからネットワーク遅延最小で速い」「外部APIだからネットワーク遅延があって遅い」ということにはなりません。 速度が問題となるような場合には、データベースの近くで稼働する推論環境へオフロードするということも考えられます。Oracle AI Database の場合は、Private AI Services Container という仕組みも提供しています。 :::note 回答生成の際にも外部の LLM にデータを送信したくない場合には、LLM をオンプレミスでセルフホスティングしたり、クラウドの専用クラスターサービスの利用や自社テナント(アカウント)内でセルフホスティングすることも考えられます。 ::: 今回はインデータベースAIの実例として、OSS の埋め込みモデル multilingual-e5-large をDB内にインポートします。文書と質問の両方をこの埋め込みモデルでベクトル化します。文章の回答やSQLを生成するLLMは、別のモデルです。こちらは外部のOCI Enterprise AI(Generative AI)の LLM を利用します。 埋め込みモデルはDB内、生成用LLMはDB外 という配置を、処理の流れに沿って確認しましょう。 処理の配置を図に示します。左側では文書のベクトル化、意味検索、契約の照会をDB内で行います。右側の生成用LLMはDBの外にあります。線に添えた情報が外部へ渡る情報です。 !DB内の検索・推論と外部LLMへ渡す情報 | 処理 | 今回の実行場所 | 使う情報 | |---|---|---| | 文書・質問の埋め込み | DB内のmultilingual-e5-large | 文書本文・質問 | | 距離検索、絞り込み、契約判定 | DBのSQL/PL/SQL | ベクトル・機種・契約・閲覧範囲 | | RAGの回答生成 | DB内のPL/SQLから外部LLMを呼ぶ | 質問・機種・取得した文書抜粋 | | SQL生成 | NL2SQLの処理から外部LLMを呼ぶ | 質問・対象ビューのメタデータなど | | Agentの実行 | DB側の制御と外部LLMの判断を組み合わせる | 指示・ツール定義・ツール実行結果など | 生成用LLMはOCI Enterprise AI(Generative AI) サービスのxai.grok-4.3をシカゴリージョンで利用し、DBは東京のAutonomous AI Database 26aiです。DBからAPIを呼ぶ場合も、渡した情報はDBの外へ出ます。「すべてのAI処理がDB内で完結する」という構成ではありません。何をDB内で処理し、何を外へ送るかを選ぶことが設計の要点です。 ここからは、埋め込みモデルの取り込みと、DB内でベクトルを生成・検索する小さなデモを見ます。 ONNXモデルをObject StorageからDBへ取り込む 準備の流れは、対応するONNX形式へ変換したモデルをObject Storageに置き、DBからDBMS_VECTOR.LOAD_ONNX_MODEL_CLOUDというPL/SQLプロシージャを呼ぶ、というものです。今回のモデルは重みが外部ファイルに分かれているため、.onnxだけでなく、付属する.jsonと.dataも同じ配置先へ置きます。DBからObject Storageへの認証にはリソースプリンシパルを使います。 ユーザー・権限・リソースプリンシパルの設定を完了した後、次のSQLを実行すると、埋め込みモデルをデータベースへインポートできます。URIはモデルの配置先へ置き換えてください。 BEGIN DBMS_VECTOR.LOAD_ONNX_MODEL_CLOUD( model_name => 'MULTILINGUAL_E5_LARGE', credential => 'OCI$RESOURCE_PRINCIPAL', uri => 'https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/<bucket>/o/<prefix>/multilingual_e5_large.onnx', metadata => JSON('{"function":"embedding","embeddingOutput":"embedding","input":{"input":["DATA"]}}') ); DBMS_VECTOR.INMEMORY_ONNX_MODEL( model_name => 'MULTILINGUAL_E5_LARGE', enable => TRUE); END; / このインポート処理が完了した後のベクトル検索では、VECTOR_EMBEDDINGというSQL関数で今登録した埋め込みモデルを呼び出してDB内でベクトル化を実行します。 なお、大きなモデルでは重みのメモリー共有も設定します。変換と配置の詳細はmultilingual-e5-largeのインポート手順、APIの引数はLOAD_ONNX_MODEL_CLOUDを参照してください。このデモで使う準備スクリプトはsql/setup/10_load_embedding_model.sqlで、ユーザー作成からの手順はAppendix A〜Cにまとめています。 データベース内の埋め込みモデルでベクトル化してみる 手元で試す際にはAppendixの準備を済ませ、変更していなければ ORAJAM41USERというユーザーで接続してください。ここで紹介する SQL はsql/demos/00b_embedding_basics.sqlでも公開しています。 埋め込みモデルが登録されていることを確認してみます SELECT model_name, mining_function, algorithm, external_data, inmemory FROM user_mining_models WHERE model_name='MULTILINGUAL_E5_LARGE'; user_mining_models は、Oracle AI Database で「現在のユーザーが所有している機械学習モデル」を一覧表示するデータ・ディクショナリ・ビューです。モデル名、用途、アルゴリズム、作成日時などを確認できます。 <details> <summary>実行結果:登録済みモデル</summary> | MODEL_NAME | MINING_FUNCTION | ALGORITHM | EXTERNAL_DATA | INMEMORY | |---|---|---|---|---| | MULTILINGUAL_E5_LARGE | EMBEDDING | ONNX | YES | YES | </details> - EMBEDDING は、埋め込みモデルであることを表しています。 - EXTERNAL_DATA は、ALGORITHM = 'ONNX' の場合、インメモリー共有を有効化できるモデルかを示す。YES:有効化可能、NO:不可。ONNX以外では意味を持たず、NO が設定される。RU 23.26.1 以降。 - INMEMORY は、ALGORITHM = 'ONNX' かつ EXTERNAL_DATA = 'YES' の場合、インメモリー共有が有効かを示す。YES:有効、NO:無効。それ以外では意味を持たず、NO が設定される。RU 23.26.1 以降。 :::note EXTERNAL_DATA = 'YES' は「外部の推論APIを使う」という意味ではありません ONNXの external data は、重み(Weight、パラメータ)などの初期化データ(initializers)を、メインのONNXモデルファイルとは別のファイルに分離して保持する仕組みです。Oracleでは、この外部初期化データを持つモデルについて、初期化データを共有メモリーに一度ロードし、複数セッションで共有できます。したがって、EXTERNAL_DATA = 'YES' は「外部の推論APIを使う」という意味ではありません。 ::: 質問を1件だけベクトルへ変換してみます 今回使う multilingual-e5-large は、検索する質問と検索対象の文書を接頭辞で区別するように学習されています。そのため、検索用途では埋め込みを生成する直前に、文書の先頭へpassage: 、質問の先頭へquery: を付けます。これはこのモデルの入力仕様で、日本語の文章にも同じ英語の接頭辞を使います。詳しい使い分けはモデルカードのUsageとFAQを参照してください。 長文は埋め込みモデルの入力データ(トークン)長の上限を踏まえて分割します。この記事のデモでは短い文書を使います。 SELECT VECTOR_EMBEDDING( MULTILINGUAL_E5_LARGE USING 'query: 管理画面が固まって操作できない' AS data ) AS embedding FROM dual; <details> <summary>実行結果:生成されたベクトルの先頭8要素</summary> [0.03598599, 0.00471110, -0.01730750, -0.02658993, 0.02554353, -0.02953884, 0.00086610, 0.10251307, ...] 全1024要素のうち先頭8要素を小数点以下8桁で表示し、残りを省略しています。SQLクライアントではベクトルのセルを開いて確認できます。 </details> 生成されたベクトルの次元数を確認します SELECT VECTOR_DIMENSION_COUNT( VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE USING 'query: 管理画面が固まって操作できない' AS data) ) AS dimensions FROM dual; | DIMENSIONS | |---| | 1024 | 1024次元とは数値の個数です。各次元が「契約」「障害」といった人が認識するような特徴を表しているわけではありません。そのため、「10番目の次元は何か?」ということは説明できません。また、同じデータでも埋め込みモデルごとに全く異なるベクトルに変換されます(ベクトル空間が異なる)ので、同じ1024次元ベクトルであっても、別のモデルで生成したベクトルを混ぜて比較することはできません。 データベース内の埋め込みモデルでベクトル検索してみる ドキュメントを格納するチャンク表(OJ41_CHUNKS)には、本文のテキスト(chunk_text列)と、ベクトル(embedding列)の両方を保存しています。 ベクトルは、原文をそのまま復元するための保存形式ではありません。検索後に本文を表示したり、LLMへ根拠として渡したりするため、元の本文テキスト(chunk_text)も保持します。 チャンク表(OJ41_CHUNKS)の主要な列だけを取り出すと次の構造になっています。説明用に省略したDDLなので、試す際にはこのまま実行せず、表の作成には35_create_demo_tables.sqlを使ってください。 -- 説明用:主要列のみ。制約・管理列などは省略。 CREATE TABLE OJ41_CHUNKS ( chunk_id VARCHAR2(24), doc_id VARCHAR2(20), chunk_text VARCHAR2(2400 CHAR), embedding VECTOR(1024, FLOAT32) ); なお、データの生成・投入と文書のベクトル化は、[Appendix C「デモデータとAI定義を準備する」](#c-デモデータとai定義を準備する)の手順に従って実施してください。以下の検索SQLは、その準備を済ませてから実行します。 この記事ではシンプルに短い16のサンプル文書をそれぞれ1チャンクにしています。 全16件の文書ID、本文の先頭100文字、ベクトルの次元数を確認してみましょう。別機種の文書や廃止済み・未公開の文書も含めたデモデータの全体です。 SELECT chunk_id, doc_id, SUBSTR(chunk_text, 1, 100) AS chunk_text_preview, VECTOR_DIMENSION_COUNT(embedding) AS dimensions FROM OJ41_CHUNKS ORDER BY doc_id; <details> <summary>実行結果:全16チャンク(本文は先頭100文字)</summary> | CHUNK_ID | DOC_ID | CHUNK_TEXT_PREVIEW | DIMENSIONS | |---|---|---|---| | KB001-01 | KB001 | 管理画面が応答しないとき<br>AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。次に管理端末から疎通を確認し、障害ログを保存します。業務への影響を確認せずに | 1024 | | KB002-01 | KB002 | E101:温度上昇の確認<br>AX-100でE101が表示された場合は吸気口の閉塞と室温を確認します。吸気口の前を空け、温度と発生時刻を記録します。装置の分解は行わず、警告が続く場合は保守窓口へ連絡します | 1024 | | KB003-01 | KB003 | E201:電源系統の警告<br>AX-100のE201は電源系統の警告です。電源ケーブルの接続と施設側の給電状況を確認し、ログを保存します。電源ユニットの交換は作業資格と契約の確認後に手配します。 | 1024 | | KB004-01 | KB004 | 管理画面停止時の旧手順<br>旧手順ではAX-100の管理画面が停止したら直ちに再起動する案内でした。この文書は廃止済みです。現行手順KB001を使用してください。 | 1024 | | KB005-01 | KB005 | 管理画面が応答しないとき<br>BX-200の管理画面が応答しない場合は、管理ポートの状態と証明書の期限を確認します。AX-100とは確認箇所が異なります。ログ取得後、管理サービスの復旧方法を保守窓口へ確認 | 1024 | | KB006-01 | KB006 | E101:認証設定の確認<br>BX-200のE101は認証設定の不整合を示します。時刻同期と認証サーバー設定を確認します。AX-100の同じコードは温度警告であり、この手順を適用しません。 | 1024 | | KB007-01 | KB007 | 通信が途切れるとき<br>AX-100で通信が断続的に切れる場合は、ケーブル損傷、リンク状態、接続先スイッチのエラー数を確認します。時刻をそろえたログを取得し、設定変更前後を比較します。 | 1024 | | KB008-01 | KB008 | ログの保存方法<br>AX-100の管理画面で「保守」から「ログ出力」を選択します。ファイル名と取得時刻を記録してください。ログには設定値が含まれるため、公開掲示板には添付せず、指定された保守窓口へ渡します | 1024 | | KB009-01 | KB009 | 設定のバックアップ<br>BX-200の設定変更前には、管理画面のエクスポート機能で設定を保存します。バックアップと変更履歴を対にして保管し、復元作業は機種とソフトウェア版を確認して実施します。 | 1024 | | KB010-01 | KB010 | ディスク残量の警告<br>CX-300で保存容量の警告が出たら、使用量とログ保持期間を確認します。監査に必要なログを保存してから、承認された保持方針に沿って整理します。無断でファイルを削除しないでください。 | 1024 | | KB011-01 | KB011 | 時刻のずれを確認する<br>CX-300のイベント時刻がずれる場合は、時刻同期サーバーへの到達性とタイムゾーンを確認します。修正前後の時刻差を記録し、ログを比較するときはその差を考慮します。 | 1024 | | KB012-01 | KB012 | 顧客C001向け保守連絡手順<br>架空顧客C001では、AX-100の障害ログを収集した後、顧客内の運用責任者へ連絡します。現地訪問は対象機器の有効な契約でONSITEが含まれる場合に手配案を作成します。 | 1024 | | KB013-01 | KB013 | 顧客C002専用の管理画面復旧手順<br>架空顧客C002のAX-100管理画面停止時には、C002専用の運用手順書に従って責任者へ連絡します。検証用識別語はC002_ONLY_ORCHIDです。この文書は | 1024 | | KB014-01 | KB014 | 管理画面復旧の検討中手順<br>検討中のAX-100管理画面復旧案です。検証用識別語はDRAFT_ONLY_MAPLEです。未承認のため公開手順として案内してはいけません。 | 1024 | | KB015-01 | KB015 | 社内担当者用の調査メモ<br>社内限定のAX-100調査メモです。検証用識別語はINTERNAL_ONLY_CEDARです。顧客向け回答の根拠には利用しません。 | 1024 | | KB016-01 | KB016 | ログ名の特殊文字の扱い<br>ログ名がowner's_logの場合も文字を変更せず記録します。<br>画面の表示例は「温度,電源」と「"警告"」です。CSVへの保存時も改行、カンマ、引用符を保持してください。 | 1024 | </details> 全16件を質問との距離が近い順に並べ、上位3件を取得します。文書側の埋め込みは準備時に作成済みです。SQL中で今回生成するのは質問側のベクトルです。 - VECTOR_EMBEDDING() SQL 関数で、ベクトルを生成します - VECTOR_DISTANCE()でベクトル間の距離を計算します。multilingual-e5-largeはコサイン類似度で比較するモデルなので、ここではコサイン距離(1 − コサイン類似度)を使用します。論文:Text Embeddings by Weakly-Supervised Contrastive Pre-training に記載あり SELECT doc_id, chunk_text, VECTOR_DISTANCE(embedding, VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE USING 'query: 管理画面が固まって操作できない' AS data), COSINE) AS distance FROM OJ41_CHUNKS ORDER BY distance, doc_id FETCH FIRST 3 ROWS ONLY; <details> <summary>実行結果:全16文書に対する近傍上位3件</summary> | DOC_ID | CHUNK_TEXT | DISTANCE(小数点以下6桁) | |---|---|---| | KB001 | 管理画面が応答しないとき<br>AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。次に管理端末から疎通を確認し、障害ログを保存します。業務への影響を確認せずに再起動しないでください。 | 0.132456 | | KB005 | 管理画面が応答しないとき<br>BX-200の管理画面が応答しない場合は、管理ポートの状態と証明書の期限を確認します。AX-100とは確認箇所が異なります。ログ取得後、管理サービスの復旧方法を保守窓口へ確認します。 | 0.152699 | | KB004 | 管理画面停止時の旧手順<br>旧手順ではAX-100の管理画面が停止したら直ちに再起動する案内でした。この文書は廃止済みです。現行手順KB001を使用してください。 | 0.153947 | </details> 質問の「固まって」に対して、KB001「管理画面が応答しないとき」が先頭になりました。2位のKB005も管理画面の不応答を扱いますが、機種はBX-200です。3位のKB004は廃止済みの旧手順です。症状に近い文書でも、そのまま顧客への案内に使えるとは限りません。 ここまでで、DB内モデルの呼び出し、VECTOR列への保存、距離による並べ替えがつながりました。次はチケットの顧客、サーバーの機種、文書の公開状態を使って、回答に使える文書へ検索範囲を絞ります。 3. チケットの顧客と機種を絞ってベクトル検索する ここまでは、質問文と似ている(ベクトル間の距離が近い)データを探す検索でした。 ここからは、問い合わせ元の顧客と問題となっているサーバー機種、文書の公開状態で絞り込む検索です。 最初にテーブルとビューの役割を確認し、その構造を使うSQLを順に実行します。 混ぜるな危険! メーカーの保守担当者が、受付済みのチケットSR001に対応する場面を考えます。 チケットから問い合わせ元の顧客C001を特定し、その顧客のサーバー台帳で保守登録番号DEV001を照合すると、機種がAX-100だと分かります。保守登録番号はメーカーがサーバー1台ごとに発行する番号です。 この対応では、別顧客のサーバーや契約、別顧客専用の文書を混在させてはいけません。また、症状が似ていても別機種の手順を案内しないよう、台帳から取得した機種で検索対象を絞ります。 SR001の対応中に別顧客の保守登録番号を入力しても、そのサーバーや契約は取得できない設計にする必要があります。担当者は全顧客のチケットに対応できますが、1回の照会・回答は選択中のチケットの顧客に限定します。異なる顧客の問い合わせにはその顧客のチケットを開いて対応します。 こんな当たり前のことをなぜここで? 後で紹介するNL2SQL(自然言語の質問からLLMがSQLを生成する仕組み)と関係があるためです。 というのは、NL2SQL では、LLMが顧客条件を付け忘れたり、誤った条件を生成したりする可能性があるため、「この顧客だけを調べて」と指示するだけでは十分ではなくアプリ自体やデータベース側の仕組みでも防御する必要があります。 そこで、アプリが選択したチケットに基づいてDB側のビューで顧客範囲を限定します。この参照経路なら、NL2SQL で生成された SQL が顧客条件を付け忘れても、ビューの外にある別顧客の行を取得してしまうことはありません。 この設計を支えるのが、業務表と文書のベクトルを同じリレーショナルDBで扱えること です。 チケット・顧客・サーバー・契約といった業務データの関係から対象を特定し、さらに文書の公開状態や顧客向けの閲覧範囲を条件にして、ベクトル検索の候補を絞ることができます。 ベクトル検索と業務データを同じデータベースで扱うと、顧客情報や契約情報を検索用の別システムへ複製せずに、業務上の条件で検索対象を絞り込めます。 この記事では、チケットの顧客情報とサーバーの機種情報を使い、その顧客に公開できる、該当機種の文書をベクトル検索します。契約の有効性や現地保守の可否も、同じデータベース内の契約情報を参照して確認します。 対応中のチケットの顧客に検索範囲を限定する仕組み まず、顧客・サーバー・契約・文書を保存するベース表を確認します。そのうえで、対応中のチケットから顧客を特定し、その顧客に応じた閲覧範囲をビューで制限する仕組みを説明します。 ベース表 ベース表には全顧客の業務データと文書を保存します。チケットを選ぶたびにデータを複製する必要はなく、後述のビューで照会対象を絞ります。 サーバー台帳OJ41_DEVICESでは、device_idが保守登録番号、modelが機種名、serial_noが製造シリアル番号を表します。 次のER図は主要キーの関係です。チケットとサーバーは顧客を介して結び付きます。文書とサーバーは直接の外部キーでは結ばず、機種と公開範囲で照合します。KB012のような顧客専用文書だけが顧客IDを持ちます。 erDiagram OJ41_CUSTOMERS ||--o{ OJ41_SUPPORT_CASES : customer_id OJ41_CUSTOMERS ||--o{ OJ41_DEVICES : customer_id OJ41_DEVICES ||--o| OJ41_CONTRACTS : device_id OJ41_CUSTOMERS o|--o{ OJ41_KNOWLEDGE : customer_id OJ41_KNOWLEDGE ||--o{ OJ41_CHUNKS : doc_id OJ41_SUPPORT_CASES { string case_id PK string customer_id FK } OJ41_DEVICES { string device_id PK string model string customer_id FK string serial_no } OJ41_CONTRACTS { string contract_id PK string device_id FK string status date start_date date end_date string service_scope } OJ41_KNOWLEDGE { string doc_id PK string model string publication string scope string customer_id FK } OJ41_CHUNKS { string chunk_id PK string doc_id FK string chunk_text vector embedding } 実テーブルのDDLはsql/setup/35_create_demo_tables.sql、全データはAppendix Gに掲載しています。 なお、契約が有効期間内であるかどうかといった「現時点」の日付が必要な場合には、システム日付ではなく OJ41_RUN 表の as_of_date 列の日付を使うようにしています。基準日はOJ41_RUNの2026-10-15に固定し、デモコードの実行日によって契約判定が変わらないようにしています。台帳・契約は各12件、文書・チャンクは各16件です。図では基準日を持つOJ41_RUN 表と一部の管理列を省略しています。 閲覧範囲を制限するための仕組み この仕組みは、対応中のチケットと顧客IDを保持するPL/SQLパッケージ と、その値を使って 行を絞るビューで 構成します。パッケージが「今、どの顧客に対応しているか」を保持し、ビューが「その顧客への回答に使えるデータ」を制約します。 !対応中のチケットの顧客IDをセッション内に保持し、ビューの条件式から参照して閲覧範囲を絞る 対応中のチケットと顧客IDの管理 現在対応しているチケットと顧客IDは、OJ41_CASE_CTXパッケージで管理します。これはこのデモで作成するPL/SQLパッケージです。open_case('SR001')で受付チケット表を引き、顧客C001をセッション内の変数へ保存します。customer_id()がその値を返し、clear_caseが消去します。 | 処理 | 種類 | 役割 | SR001の場合 | |---|---|---|---| | open_case('SR001') | プロシージャ | チケット表からチケットIDと顧客IDを取得し、セッション内の変数に保存する | SR001とC001を保存する | | customer_id() | 関数 | 保存した顧客IDを返す。ビューが顧客範囲を絞るために使う | C001を返す | | clear_case | プロシージャ | 保存したチケットIDと顧客IDを消去する | 両方をNULLに戻す | これらはsql/setup/35_create_demo_tables.sqlのOJ41_CASE_CTXのパッケージ本体(PACKAGE BODY)に定義されています。以下は値の保存・読み出し・消去に関係する部分の抜粋です。例外処理と、チケットの切り替えを識別する管理用カウンターは省略しています。 チケットと顧客IDの保存 チケットと顧客IDの値の保存先は、パッケージ本体の非公開変数です。同じパッケージを使っても、値はDBセッションごとに保持されます。 g_case VARCHAR2(20); -- チケットID g_customer VARCHAR2(10); -- 顧客ID チケットの対応開始 PL/SQLプロシージャopen_caseは、引数p_case_idで指定したチケットを表から探し、SELECT ... INTOで上記の g_case、g_customer の二つの変数へ値を格納します。実装では、取得前にclear_caseを呼び、前の値を消去しています。 SELECT case_id, customer_id INTO g_case, g_customer FROM OJ41_SUPPORT_CASES WHERE case_id = UPPER(p_case_id); 顧客IDの取得 customer_id()は、g_customerに保持した値を返します。ビューは非公開変数を直接読む代わりに、この関数を呼び出します。 FUNCTION customer_id RETURN VARCHAR2 IS BEGIN RETURN g_customer; END; チケット情報のクリア clear_caseは、二つの変数をNULLに戻します。処理が終わった接続に、前のチケットの情報を残さないための消去処理です。 PROCEDURE clear_case IS BEGIN g_case := NULL; g_customer := NULL; END; DBセッションごとの独立性 チケットIDがSR001のチケットを開くと、そのDBセッションは顧客IDとしてC001を保持します。別のセッションでチケットSR002を開くと、そのセッションが保持する顧客IDはC002になります。一方でclear_caseを実行しても、他方のセッションの値は変わりません。状態は担当者のアカウントではなくDBセッションに属するため、接続プールを使う場合はリクエストごとに設定・消去し、処理が終わるまで同じ接続を別のリクエストへ渡さないようにします。なお、この仕組みは顧客データの混入を減らすもので、担当者がチケットを扱えるかの認可とは異なります。実システムでは別途認可の検討が必要です。 閲覧範囲を制限するビュー - ビューはOJ41_CASE_CTX.customer_id()が返す顧客IDを使い、ベース表から返す行を絞ります。 - 文書には、顧客IDに加えて公開状態と公開範囲の絞り込み条件も適用します。 前節のベクトル基礎のデモではチャンク表を直接読んでいましたが、ここからは次のビューを使います。 | ビュー | 表から取り出す範囲・付加する情報 | 利用先 | |---|---|---| | OJ41_VISIBLE_DEVICES | 対応中のチケットの顧客のサーバー | 保守登録番号と機種の特定 | | OJ41_VISIBLE_CONTRACTS | 上記サーバーの契約と、有効性・現地保守対象の判定列 | SQL照会、NL2SQL、契約ツール | | OJ41_VISIBLE_KNOWLEDGE | 公開済みで、共通またはチケット顧客専用の文書 | 文書の閲覧範囲 | | OJ41_VISIBLE_CHUNKS | 上記文書の本文・ベクトルと機種・タイトル | ベクトル検索、RAG、文書検索ツール | <details> <summary>ビューの条件をSQLで読む(説明用抜粋)</summary> -- 説明用:作成は35_create_demo_tables.sqlで行う。 CREATE OR REPLACE VIEW OJ41_VISIBLE_DEVICES AS SELECT d.* FROM OJ41_DEVICES d WHERE d.customer_id = OJ41_CASE_CTX.customer_id(); CREATE OR REPLACE VIEW OJ41_VISIBLE_KNOWLEDGE AS SELECT k.* FROM OJ41_KNOWLEDGE k WHERE k.publication = 'PUBLISHED' AND OJ41_CASE_CTX.current_case() IS NOT NULL AND (k.scope = 'PUBLIC' OR (k.scope = 'CUSTOMER' AND k.customer_id = OJ41_CASE_CTX.customer_id())); CREATE OR REPLACE VIEW OJ41_VISIBLE_CHUNKS AS SELECT c.*, k.model, k.title FROM OJ41_CHUNKS c JOIN OJ41_VISIBLE_KNOWLEDGE k ON k.doc_id = c.doc_id; </details> これらのビューも、前述の35_create_demo_tables.sqlで定義しています。チケットが未選択なら、これらのビューは0件です。文書ではDRAFT・RETIREDとINTERNALを除外します。ここでのINTERNALの除外は顧客向け回答に使う文書の範囲を定めるためで、保守担当者本人の社内閲覧権限を判定しているわけではありません。 :::note info コラム:ハーネスで、参照できる範囲を制限する 近年のエージェント設計では、モデル呼び出しやツール実行、状態管理、検査など、LLMの周囲の実行を支える仕組みを「ハーネス(harness)」と呼びます。例えばAnthropicは、モデルを呼び出してツールへ処理を振り分けるループをハーネスとして説明しています。ハーネスと実行環境の分担 この観点では、「別顧客を調べないで」とプロンプトに書くことに加え、対応中のチケットに基づくビューと生成SQLの参照先制限で、生成されたSQLが参照する範囲を制限することはハーネスの一種と言えます。これは、LLMが指示を守ることだけに依存せず、実行側にも制約を置く工夫です。ここでは、実行側で「どのデータを参照できるか」を制限しています。次に、契約ルールを使って「どう判定するか」もDB側へ置く方法を見ていきます。所有者ユーザーへの権限制御が別途必要な点は変わりません。 ::: 契約の判定も LLM に推測させずビューで判定する 「このサーバーは現地保守の対象か」という問いに答える方法として、契約情報と判定ルールをLLMへ渡して推測(推論)させることが考えられます。例えば、プロンプトで次のように指示する方法です。 > 契約状態がACTIVEで、基準日が契約の開始日から終了日までの範囲内(両端を含む)なら、有効な契約です。さらにサービス範囲がONSITEなら、現地保守の対象と判断してください。 この方法では、条件の読み取りと日付の比較をLLMに任せます。また、NL2SQLに同じルールを伝え、その都度、条件を組み込んだSQLを生成させる方法もあります。 しかし、LLM は間違えることがあります。また、LLM の動作には揺らぎがあり同じ条件でも異なる判定をすることがあります。 決定論的に判定できることはプログラムコードで決定論的に判定すべきです。 今回のデモでは、このルールをDBのビューのCASE式で定義します。 契約表の状態(status)、開始日(start_date)、終了日(end_date)、サービス範囲(service_scope)と基準日(as_of_date)が同じなら、DBのビューは常に同じ判定を返します。 つまり、CASE式でDBに決定論的に判定させる わけです。 判定結果の is_activeは契約の有効性、onsite_eligibleは現地保守の対象かどうかを表し、結果はYまたはNになります。 -- OJ41_VISIBLE_CONTRACTSの計算列を抜粋。cは契約、rは基準日の表。 CASE WHEN c.status = 'ACTIVE' AND r.as_of_date BETWEEN c.start_date AND c.end_date THEN 'Y' ELSE 'N' END AS is_active, CASE WHEN c.status = 'ACTIVE' AND r.as_of_date BETWEEN c.start_date AND c.end_date AND c.service_scope = 'ONSITE' THEN 'Y' ELSE 'N' END AS onsite_eligible 例えば、契約がACTIVEで有効期間内でも、サービス範囲がREMOTEなら、is_activeはY、onsite_eligibleはNです。LLMはこの結果を使って回答し、NL2SQLではonsite_eligible = 'Y'のように判定列を条件にするSQLを生成します。状態・期間・範囲の判定式を毎回生成する必要がなくなります。画面表示やAgentの契約ツールも同じビューを参照すれば、契約ルールをそれぞれに重複して実装せずに済みます。 :::note info コラム:契約判定をDBへ置くことと、ハーネスの関係 契約判定をビューのCASE式に置く工夫も、ハーネスを支える業務ロジックの一部と捉えられます。LLMの出力には揺らぎや誤りがあり得ますが、契約の可否はDBのビューが決定論的に返す判定値を使います。LLMそのものが決定論的に振る舞うことを期待するのではなく、確定したルールの適用をLLMの外で強制する設計です。 少し冗談めかして言えば、「VIEW as a Harness」 と呼んでもいいかもしれませんね。 ::: なお、この段階では契約が無効な行もビューに残します。期限切れや解約済みの問い合わせにも、「なぜ現地保守の対象ではないか」を説明するためです。第5章のNL2SQLではLLMに有効性の業務ルールを一から判断させず、この判定済みの列を使うSQLを生成させます。 デモA:リレーショナルデータベースによる ベクトル検索 & JOIN & フィルタリング(機種で絞って、ベクトル距離で並べる) デモAのSQL:sql/demos/01_vector_search.sql 始めに担当者が受付番号SR001を選んだことを、PL/SQL OJ41_CASE_CTX.open_case('SR001') で設定します。 BEGIN OJ41_CASE_CTX.open_case('SR001'); END; / open_caseプロシージャは受付チケット表(OJ41_SUPPORT_CASES )から顧客ID(customer_id)を取得して、この接続のチケットコンテキストに保持します。チケットコンテキストとは、現在対応している受付番号・顧客を処理中だけ保持する状態です。 続いて、同じDBセッションで後続のSELECTを実行してください。 SELECT s.case_id, c.customer_id, c.customer_name FROM OJ41_SUPPORT_CASES s JOIN OJ41_CUSTOMERS c ON c.customer_id=s.customer_id WHERE s.case_id=OJ41_CASE_CTX.current_case(); この SELECT は、OJ41_CASE_CTX.current_case()で、チケットコンテキストから現在対応している受付番号を取得して、顧客表(OJ41_CUSTOMERS)から顧客ID(customer_id)と顧客名(customer_name)を取得します。 <details> <summary>実行結果例:選択中の受付チケットと顧客</summary> | CASE_ID | CUSTOMER_ID | CUSTOMER_NAME | |---|---|---| | SR001 | C001 | あおば商事(架空) | </details> :::note Database Actions TIPS Oracle Database Actionsでは、チケットを設定するPL/SQLと後続のSELECT文をまとめて、1回のスクリプト実行で動かしてください。 同じワークシートでも、文を別々に実行するとチケットの状態は引き継がれません。デモAはsql/demos/01_vector_search.sql全体を実行します。検索ごとに結果を確認する場合は、チケット設定・対象のSELECT・チケット解除を一つのスクリプトにまとめます。Database Actionsのセッション仕様 ::: 続けて、その顧客の契約を確認します。OJ41_VISIBLE_CONTRACTS ビューは選択中のチケットの顧客の契約だけを返すビューです。チケット未選択なら0件です。上で SR001 を設定していれば該当する契約の一覧が返るはずです。 SELECT device_id, model, contract_id, status, is_active, onsite_eligible FROM OJ41_VISIBLE_CONTRACTS ORDER BY device_id; <details> <summary>実行結果例:顧客C001の契約一覧(8件)</summary> | DEVICE_ID | MODEL | CONTRACT_ID | STATUS | IS_ACTIVE | ONSITE_ELIGIBLE | |---|---|---|---|---|---| | DEV001 | AX-100 | CT001 | ACTIVE | Y | Y | | DEV002 | AX-100 | CT002 | ACTIVE | N | N | | DEV003 | AX-100 | CT003 | CANCELLED | N | N | | DEV004 | AX-100 | CT004 | ACTIVE | Y | N | | DEV005 | AX-100 | CT005 | ACTIVE | Y | Y | | DEV006 | AX-100 | CT006 | ACTIVE | Y | Y | | DEV007 | BX-200 | CT007 | ACTIVE | N | N | | DEV008 | BX-200 | CT008 | ACTIVE | Y | Y | </details> A0では、その契約一覧の範囲で保守登録番号DEV001を照合します。 SELECT device_id, model, contract_id, status, is_active, onsite_eligible FROM OJ41_VISIBLE_CONTRACTS WHERE device_id = 'DEV001'; <details> <summary>実行結果例:DEV001の契約と機種</summary> | DEVICE_ID | MODEL | CONTRACT_ID | STATUS | IS_ACTIVE | ONSITE_ELIGIBLE | |---|---|---|---|---|---| | DEV001 | AX-100 | CT001 | ACTIVE | Y | Y | 確かに契約があり、基準日(2026年10月15日)時点で有効で、サーバーの機種は AX-100 で、オンサイト保守も可能であることがわかりました。 </details> DEV001は契約CT001に対応するAX-100です。別顧客の番号や未登録の番号は取得できません。IS_ACTIVEは契約が基準日に有効ならY、ONSITE_ELIGIBLEは現地保守の対象ならYです。DEV002のような期限切れの契約では、行は取得できてもこれらの値はNになります。 次のA1のベクトル検索では、この結果のAX-100をWHERE句に指定して絞り込みます。 SQLの条件を読み取りやすいように、ここではA0で確認した値AX-100を直接記述しています。 SELECT doc_id, title, VECTOR_DISTANCE(embedding, VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE USING 'query: 管理画面が固まって操作できない' AS data), COSINE) AS distance FROM OJ41_VISIBLE_CHUNKS WHERE model='AX-100' AND embedding IS NOT NULL ORDER BY distance, doc_id FETCH FIRST 3 ROWS ONLY; <details> <summary>実行結果例:A1の検索結果3件</summary> 距離は小数点以下6桁に丸めています。 | DOC_ID | TITLE | DISTANCE | |---|---|---| | KB001 | 管理画面が応答しないとき | 0.132456 | | KB008 | ログの保存方法 | 0.193369 | | KB002 | E101:温度上昇の確認 | 0.196404 | 1位のKB001は管理画面停止の手順です。ベクトル距離が小さい(近い)順に上位3件を取得していますので2位・3位も候補として返りますが、必ずしも質問への回答に役立つデータであるとは限りません。 </details> このSQLでは、WHEREが対象機種などの業務条件を指定し、VECTOR_DISTANCEが質問との距離を計算します。ORDER BYで近い順に並べ、FETCH FIRSTで上位3件を返します。通常のSQLに「距離」という並べ替え基準が加わったと読むと理解しやすくなります。 ベクトル検索では、KB001「管理画面が応答しないとき」が1位になりました。 それでは、INSTR(chunk_text, '固まって') > 0による部分一致検索だとどうなるでしょうか? 同じ閲覧範囲・機種で、文字列「固まって」を含む文書を探します。 SELECT doc_id, title FROM OJ41_VISIBLE_CHUNKS WHERE model='AX-100' AND INSTR(chunk_text, '固まって') > 0; <details> <summary>実行結果例:A2の部分一致検索</summary> 取得行数: 0件 。 </details> 0件です。 言葉が一致しない場合には部分一致検索では候補を見つけることができませんでしたが、ベクトル検索であれば候補を探せることがわかりました。 デモデータには同じエラーコードE101が機種によって異なる意味を持つ文書も用意しています。 次のA3では機種条件を外し、AX-100の温度上昇とBX-200の認証設定が一緒に返ることを確認します。どちらもE101ですが、対処すべき症状は異なります。ベクトル検索でエラーコードを探せても、対象機種の指定は必要です。 <details> <summary>オプション・デモA3:機種を絞らずE101を検索した結果</summary> SELECT doc_id, model, title, VECTOR_DISTANCE(embedding, VECTOR_EMBEDDING(MULTILINGUAL_E5_LARGE USING 'query: E101の対処は?' AS data), COSINE) AS distance FROM OJ41_VISIBLE_CHUNKS WHERE embedding IS NOT NULL ORDER BY distance, doc_id FETCH FIRST 3 ROWS ONLY; | DOC_ID | MODEL | TITLE | DISTANCE | |---|---|---|---| | KB002 | AX-100 | E101:温度上昇の確認 | 0.142341 | | KB006 | BX-200 | E101:認証設定の確認 | 0.148356 | | KB003 | AX-100 | E201:電源系統の警告 | 0.152087 | </details> ここまでのデモで、ビューによる閲覧範囲の制限(現在対応中の顧客に限定)が可能であること、ベクトル検索により異なる表現、言い換えを含む質問で関連文書を取得できること、リレーショナル表の業務データと組み合わせたフィルタリングの有用性がわかりました。 <details> <summary>参考:別の受付チケットに切り替える</summary> SR001でDEV009を照会するとビューによる閲覧範囲制限で結果は 0件となるはずですが、 SR002を開くと、その顧客C002のサーバーを照会できます。 BEGIN OJ41_CASE_CTX.open_case('SR002'); END; / SELECT device_id FROM OJ41_VISIBLE_DEVICES ORDER BY device_id; | DEVICE_ID | |---| | DEV009 | | DEV010 | | DEV011 | | DEV012 | C002専用文書KB013はこのチケットで利用でき、C001専用文書KB012は検索対象から外れます。 </details> このチケットの照会を終えたら、保持した状態を消去します。別顧客のチケットへ移る場合は、例えばopen_case('SR002')で明示的に切り替えます。存在しない受付番号を指定した場合は、古いチケットを消去してエラーにします。 BEGIN OJ41_CASE_CTX.clear_case; END; / 検索で閲覧範囲制限を考慮した上で質問に対する回答作成に役立つ候補文書を見つけることはできるようになりました。次は、見つけた文書を読んで回答を作る処理を加えます。 4. 検索した文書を根拠にRAG(検索拡張生成)で回答する 根拠に基づいて答えるために、質問のたびに資料を渡す 検索拡張生成(RAG:Retrieval-Augmented Generation)は、質問に関連する情報を検索し、その情報をLLMへ渡して回答を生成する構成です。先ほどの意味検索が、回答の根拠を取り出す部分になります。 !image.png LLMは自然な文章を作れても、回答が自社の手順や最新の資料に合っているとは限りません。そこで、質問のたびに関連資料を検索し、その内容を根拠に答えるよう指示します。今回なら「AX-100の管理画面が開かない」という質問に、メーカーの該当手順を添えて LLM に渡します。文書を改訂した場合は、本文とベクトルを更新して検索対象へ反映します。 RAGには、誤った情報の生成を減らすこと、社内固有の知識を利用すること、更新された情報を回答に反映することが期待できます。 !image.png ただし、資料を渡すだけで正しさが保証されるわけではありません。質問に合う資料を取得できたか、その資料に沿って答えたかの両方を確認します。背景はRAGの基礎:LLMの限界とRAGによる解決への道、RAGの目的と利点でも紹介しています。 文書をベクトル化する際のチャンキングにも注意が必要です。 チャンクが小さすぎると、前提や注意事項が抜けます。大きすぎると、質問に関係のない記述が増えます。単に文字数で切るだけでなく、見出しや手順のまとまり、文書ID、版を保持することが、検索後の回答にも効いてきます。 また、チャンクサイズや検索で取得する結果セットの件数は、ベクトル検索の精度に影響します。 !image.png この記事では、文書の事前ベクトル化は準備時に済ませているものとして、質問を受け取ってから回答を返すまでの処理を見ていきます。 検索・拡張・生成の流れを、DB内のPL/SQLでつなぐ このデモでは、RAGの一連の処理を、PL/SQLパッケージ OJ41_RAG の関数 answer_question にまとめています。チケットIDと質問を渡すと、文書の検索、LLMへの入力構築、回答生成、回答の検査を行い、結果をJSONで返します。この関数の呼び出し例は、後の「デモB」で紹介します。 ここでは、検索するタイミング、資料を入力コンテキストへ加える方法、回答を検査する順序をDB内のPL/SQLで定めています。LLMの推論はOCI Enterprise AI(Generative AI)の Grok 4.3 で行い、DBからリソースプリンシパルで API を呼び出します。LLMが次の処理を選ぶ構成ではなく、条件分岐を含む決められた流れの中で回答生成を呼び出します。 flowchart TD Q["質問+選択中のチケット"] --> R["検索<BR/>DBで保守登録番号を照合して機種・閲覧範囲に合う文書を取得"] R --> H{"候補文書があるか"} H -->|ない| N["根拠不足を返す<br/>LLMは呼ばない"] H -->|ある| A["拡張<br/>質問+特定した機種+文書ID・本文+回答指示をLLMへ渡す入力コンテキストとして組み立てる"] A --> G["生成<br/>DBから 外部LLM を呼び出し、資料を根拠に回答を生成する"] G --> V{"DB内のPL/SQLでJSON形式・文書ID・引用を検査"} V -->|適合| O["回答または根拠不足を返す"] V -->|不適合| E["検査エラーで停止"] このフロー図を実装しているのが、68_rag_body.sql の OJ41_RAG.answer_question です。関数の冒頭でチケットを開き、保守登録番号が指定されていれば、その顧客のサーバー台帳から機種を確定します。続いて、閲覧範囲と機種に合う文書を検索し、取得した文書IDと本文をJSON配列 docs に格納します。 以下は、文書の検索が終わった後の処理 を抜き出したPL/SQLです。フロー図の「候補文書があるか」から「拡張」「生成」「回答の検査」までに対応します。docs.get_size() は取得した文書の件数を返します。変数の宣言や検索処理は省略しているため、この抜粋だけでは実行できません。 -- 検索結果が0件なら、LLMを呼ばずに「根拠不足」とする IF docs.get_size()=0 THEN checked:='{"status":"insufficient","claims":[]}'; ELSE -- 拡張:質問・機種・検索した文書を、回答指示とともに入力へ加える payload.put('question',p_question); payload.put('db_resolved_model',model_name); payload.put('documents',docs); prompt:=TO_CLOB(instruction)||CHR(10)||payload.to_clob(); -- 生成:組み立てた入力を外部LLMへ渡す raw_answer:=DBMS_CLOUD_AI.GENERATE( prompt=>prompt,profile_name=>'OJ41_BUSINESS_AI',action=>'chat'); -- 検査:回答のJSON形式・文書ID・引用を検索結果と照合する checked:=OJ41_ANSWER_GUARD.validate_json(raw_answer,docs.to_clob()); END IF; payload は質問・機種・検索結果をまとめるJSONオブジェクト、instruction は回答ルール、raw_answer はLLMが返した回答です。回答の検査を担当する OJ41_ANSWER_GUARD.validate_json の実装は 66_answer_guard_body.sql にあります。検査に適合すれば、answer_question は回答などを含む結果を返します。正常終了時も例外発生時も、関数内でチケットの状態を消去します。 RAGのLLM呼び出しには、Oracle AI Database 26ai の Select AI chat 機能を使います。LLMの接続先・認証・生成パラメータは、AIプロファイル OJ41_BUSINESS_AIに設定しています。付録Cで準備するプロファイルで、後のAgentと共用します。定義全文は64_business_ai_template.sqlを参照してください。Python版もrag.pyに残しています。 検索によって、LLMへ渡すコンテキストはどう変わるか 利用者が入力するのは「DEV001の管理画面が開かない。最初に何を確認する?」だけです。検索後には、DBで特定した機種と、文書ID・本文を加えた次のようなJSONをユーザーメッセージとして渡します。これはPL/SQLが組み立てる形式に合わせた例で、文書はKB001の1件だけを示しています。実際には取得した最大3件をdocumentsへ入れます。 { "question": "DEV001の管理画面が開かない。最初に何を確認する?", "db_resolved_model": "AX-100", "documents": [ { "doc_id": "KB001", "text": "管理画面が応答しないとき AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。次に管理端末から疎通を確認し、障害ログを保存します。業務への影響を確認せずに再起動しないでください。" } ] } このJSONに回答のルールを添えて、一つのプロンプトとして渡します。68_rag_body.sqlの指示から抜粋すると、次の内容です。 提示資料だけを根拠とし、他機種の手順、推測、資料にない操作を追加しないでください。 質問の症状に関係しない手順は、提示資料に含まれていても回答に使わないでください。 契約照会や訪問の確約はできません。質問に答える根拠が足りなければ insufficient としてください。 質問そのものを書き換えるのではなく、その質問を解釈して回答するための情報を添えています。これがRAGの「拡張」に当たります。LLMへ渡すのは検索で取り出した本文であり、検索に使った1024次元のベクトルではありません。 このデモでは、契約の有効性をRAGの検索条件にしていません。契約が無効でも、閲覧を許可された文書から確認手順を案内するシナリオだからです。デモBは文書に基づく回答、デモCは契約条件の照会、デモDは両者の組み合わせを扱います。「有効契約の顧客だけが読める文書」を扱う業務なら、契約表を検索条件へ組み込む設計が適切です。リレーショナルDB内のベクトル検索なら、その条件もJOINやEXISTSで表現できます。 デモB:答えがある質問と、根拠が足りない質問を比べる VS Code SQL DeveloperでDBMS Outputを有効にし、次の各ブロックを実行します。全文は01b_rag.sqlにあります。 DECLARE r CLOB; BEGIN r:=OJ41_RAG.answer_question('SR001','DEV001の管理画面が開かない。最初に何を確認する?'); OJ41_ANSWER_GUARD.print_clob(r); END; / DECLARE r CLOB; BEGIN r:=OJ41_RAG.answer_question('SR001','AX-100のE999の修理方法は?'); OJ41_ANSWER_GUARD.print_clob(r); END; / DECLARE r CLOB; BEGIN r:=OJ41_RAG.answer_question('SR001','AX-100の保証延長料金を日本円で教えて。'); OJ41_ANSWER_GUARD.print_clob(r); END; / <details> <summary>実行結果例:デモBの回答・引用と根拠不足</summary> SR001での実行結果から、status・claims・llm_callsを抜粋しています。回答の文言は実行ごとに変わります。 DEV001の管理画面が開かない { "status": "answered", "claims": [ { "text": "AX-100の管理画面が開かない場合、まず電源ランプとLANケーブルを確認します。", "doc_id": "KB001", "quote": "AX-100の管理画面が開かず、応答が止まった場合は、まず電源ランプとLANケーブルを確認します。" } ], "llm_calls": 1 } この結果は、登録済みの文書に照らして期待どおりです。DEV001の機種はAX-100で、公開済みの共通文書KB001には「まず電源ランプとLANケーブルを確認します」と記載されています。回答はこの手順に沿っており、引用もKB001の本文と一致しています。status: answered と llm_calls: 1 は、検索した文書をLLMへ渡して回答を生成したことを示します。 AX-100のE999 { "status": "insufficient", "claims": [], "llm_calls": 0 } この結果も期待どおりです。登録済みの16文書には、E999に関する記述がありません。このRAGの検索処理では、質問にエラーコードがあれば、その文字列を本文に含む文書に絞ってからベクトル距離で並べます。そのため候補が0件になり、PL/SQLがLLMを呼ばずに insufficient を返します。llm_calls: 0 はこの分岐に対応します。ベクトル距離だけで「答えがない」と判定した結果ではありません。 AX-100の保証延長料金 { "status": "insufficient", "claims": [], "llm_calls": 1 } この結果も期待どおりです。登録済みの16文書には、保証延長の料金表や金額の記載がないため、金額を回答せず insufficient を返すのが期待する動作です。この質問にはエラーコードによる絞り込みがなく、機種と閲覧範囲に合う文書から距離順に上位3件が取得されます。ただし、検索結果(候補文書)があることと、そこに質問への答えが記載されていることは別です。llm_calls: 1 は候補文書をLLMへ渡したことを示し、掲載結果ではLLMが料金を答える根拠が不足していると判断しています。E999の例との違いは、検索結果が0件なのではなく、取得した文書に答えがないことです。 </details> PL/SQLは取得した最大3件の文書と質問・機種をLLMへ渡します。返されたJSONについて、文書IDが取得結果に存在するか、引用が原文に含まれるかを検査します。実装は68_rag_body.sqlと66_answer_guard_body.sqlです。 :::note info コラム:生成結果を検査することも、ハーネスの役割 このRAGのPL/SQLコードは、LLMの回答をそのまま表示せず、JSON形式・文書ID・引用を検査します。不正な出力は検査エラーとして止め、検索候補がない場合はLLMを呼びません。モデルへの指示に加えて、出力を受け入れる条件をコードで定めています。 ただし、引用が原文に含まれているかの確認と、回答の説明が引用の内容に沿っているかの確認は別です。この検査だけで回答全体の正しさを保証するわけではありません。 ::: | ケース | 実機で確認した結果 | 確認する点 | |---|---|---| | 管理画面が開かない | 電源ランプ・LANケーブルの確認、KB001を引用 | 説明と引用が対応するか | | E999 | 候補0件でLLMを呼ばない | 未知のコードを補っていないか | | 保証延長料金 | insufficient、claimsは空 | 取得文書に答えがないと判断できるか | LLMの文言は毎回同じになるとは限りません。表の結果を確かめるときは、文章の完全一致ではなく、必要な確認手順と根拠が含まれるかを見ます。 検索の失敗と生成の失敗を分けて直す 正しい手順が取得結果に入っていなければ、回答指示だけを変えても根拠は増えません。質問の表現、機種条件、チャンクの切り方、検索件数を見直します。正しい手順を取得できたのに回答が誤っている場合は、資料の渡し方や回答指示、引用との対応を調べます。 この引用検査は、文書IDが取得結果に存在し、引用文字列がその本文に含まれるかを確かめるものです。意味の正しさまで検証するものではありません。回答に根拠が示されているかに加え、引用の内容と回答の説明に食い違いがないかも確認します。 RAGで技術手順は説明できました。しかし、「契約が何件あるか」「有効期限内か」まで文書の近さで決めるのは適切ではありません。次は、契約表の条件照会を自然言語で行います。 5. NL2SQL で契約情報を照会する 閲覧範囲を制限したビューを、NL2SQL で検索する 「現地保守の対象サーバーを一覧にしてほしい」という質問を、SQLを書かずに問い合わせられるようにします。自然言語の質問からLLMがSQLを生成する処理を、NL2SQL(Natural Language to SQL)と呼びます。 LLMには質問とともに、利用できる表や列の情報、業務用語の説明などを渡します。生成されたSQLをDBで実行することで、リレーショナル表にある業務情報を照会できます。 この章では、Oracle AI DatabaseでNL2SQLを実現する機能「Select AI」を使います。Select AIの概要 !image.png LLM で SQL を生成する NL2SQL では生成されたSQLが適切な閲覧範囲を指定するとは限りません。例えば、契約表を直接参照するSQLで顧客条件が抜けると、別顧客の契約まで結果に含まれる可能性があります。「対応中の顧客だけを調べて」とLLMに指示することに加えて、実行側でも参照できる範囲を制限する必要があります。 そこで、第3章で用意した OJ41_VISIBLE_CONTRACTS ビューを使います。このビューは、同じDBセッションの OJ41_CASE_CTX.customer_id() 関数が返す顧客IDでサーバー台帳を絞り、そのサーバーの契約だけを返します。open_case('SR001') プロシージャでチケットSR001を選択していれば顧客C001の契約が対象となり、チケット未選択なら0件です。生成SQLがこのビューを参照する限り、顧客条件を付け忘れても別顧客の契約行は取得されません。 さらに、生成SQLがベース表を直接参照して制限を迂回しないよう、Select AIの object_list に閲覧範囲を適用済みのビューなどを指定し、enforce_object_list=true で参照先を制限します。 !image.png 図中のSQLは機能を説明するための例です。このデモで使う設定・オブジェクト名は、後述のSQLを参照してください。 ビューによる行の限定と、生成SQLの参照先制限を組み合わせる 構成です。具体的な対象一覧と設定は、続くデモCで紹介します。これはNL2SQLの参照経路を制限する仕組みであり、第3章で説明した担当者本人の認可やDB権限の分離も別途必要です。 契約照会に使う OJ41_VISIBLE_CONTRACTSビューの列は、次のとおりです。定義は 35_create_demo_tables.sql にあります。 OJ41_VISIBLE_CONTRACTSビュー | 列名 | 意味 | 問い合わせでの使い方 | |---|---|---| | contract_id | 契約ID | 契約を識別する | | device_id | メーカーが付与した保守登録番号 | 対象サーバーを照合・一覧表示する | | start_date | 契約開始日 | 契約期間を確認する | | end_date | 契約終了日 | 契約期間を確認する | | status | 契約状態。ACTIVE または CANCELLED | 契約状態を確認する。ACTIVE だけでは期間内かどうかは判断できない | | service_scope | サービス範囲。ONSITE または REMOTE | 現地保守かリモート保守かを確認する | | customer_id | 契約対象サーバーの顧客ID | 対応中のチケットの顧客であることを確認する | | model | サーバーの機種 | 機種ごとに絞り込み・集計する | | as_of_date | 契約の有効性を判定する基準日 | このデモでは2026年10月15日時点の判定であることを確認する | | is_active | 基準日時点で契約が有効なら Y、それ以外は N | 有効な契約に絞る | | onsite_eligible | 基準日時点で契約が有効で、現地保守の対象なら Y、それ以外は N | 現地保守の対象サーバーを一覧表示・集計する | is_active と onsite_eligible は、契約データと基準日からビューの CASE 式が計算する列です。LLMには契約の有効性を推測させず、例えば onsite_eligible = 'Y' のように、判定済みの列を使うSQLを生成させます。期限切れや解約済みの契約もビューには残るため、対象外の理由を調べる照会にも使えます。 この仕組みで顧客範囲を限定しても、LLMが同じ顧客の中で誤った列や条件を選ぶ可能性は残ります。続くデモCでは、現地保守の対象サーバーを調べる質問を使い、列の意味を伝える注釈がSQL生成にどう影響するかを確認します。 デモC:現地保守の対象サーバーを自然言語で調べる 保守担当者が、対応中のチケットSR001の顧客について、現地保守を利用できるサーバーを一覧で確認する場面です。目標は、基準日時点で対象となる保守登録番号DEV001・DEV005・DEV006・DEV008を昇順で取得することです。利用者が表名や列名を知らなくても、次の質問で調べられるようにします。 > この受付案件の顧客について、基準日時点で現地保守の対象となるサーバーの保守登録番号を昇順で教えてください。 ここでいう「受付案件」はチケットのことです。以下の質問文と実行結果例は、検証時の表記のまま掲載しています。 質問文には、「受付案件」がどの表に対応し、「現地保守の対象」がどの列で判定されるかは明示されていません。 Select AIが付加するDBのメタデータも含めて、LLMがその対応を読み取れることが必要です。業務用語と実際のデータ構造の対応を十分に渡さない素朴なNL2SQLでは、存在しない表や列を補ったり、必要な条件を落としたりする失敗が起こり得ます。 成功率を上げるには、表・ビュー・列の構造に加え、業務用語との対応もLLMへ伝える必要があります。今回は、その説明をDBのデータディクショナリへ ANNOTATION(注釈) として登録します。利用者が質問のたびに説明を書き足す代わりに、Select AIが注釈をメタデータとしてLLMへの入力に含めます。 !image.png 図中のSQLは機能を説明するための例です。このデモで使う設定・オブジェクト名は、後述のSQLを参照してください。 Select AI には、NL2SQL の精度改善のための様々な機能があります。今回は、annotationsと object_list / enforce_object_list を使っています。 !image.png まず、生成SQLが参照してよい範囲を決めます。今回のデモに関係するOJ41で始まる表・ビューから、閲覧範囲の制限を迂回するものを除きます。 | 扱い | 表・ビュー | 理由 | |---|---|---| | 含める | OJ41_VISIBLE_CONTRACTS、OJ41_VISIBLE_DEVICES、OJ41_VISIBLE_KNOWLEDGE、OJ41_VISIBLE_CHUNKS | チケットの顧客や文書の公開範囲を適用済みのビュー | | 含める | OJ41_RUN、OJ41_BULK_PARTS | 固定基準日やロード進捗。顧客別の契約や制限対象の本文を含まない | | 除く | OJ41_CUSTOMERS、OJ41_SUPPORT_CASES、OJ41_DEVICES、OJ41_CONTRACTS | ビューを通さず別顧客の行を参照できるベース表 | | 除く | OJ41_KNOWLEDGE、OJ41_CHUNKS、OJ41_BULK_DOCS、OJ41_BULK_STAGE | 顧客専用・内部向けの本文を含むベース表と大量ロード用の複製 | OJ41_BULK_PARTS は大量ロードの準備で作成する表です。まだ作成していない場合は、以下の両プロファイルの object_list からこの項目だけを除いてください。付録Cの準備コードは、実際に存在する表を確認して一覧を作成します。 object_listはメタデータの対象を選び、enforce_object_list=trueは生成SQLの参照先をその一覧に制限します。両プロファイルで同じ一覧を使い、object_list_mode=allを明示します。表・ビュー・列のメタデータは両方へ渡し、annotationsだけを切り替える比較です。属性の仕様、注釈によるSQL生成の改善 !image.png 各テストケースを実行する前に、対応中のチケットを SR001 に設定します。 BEGIN OJ41_CASE_CTX.open_case('SR001'); END; / 1. 注釈を含めずにSQLを生成する Select AI を使用するためには、あらかじめ AIプロファイル を定義しておく必要があります。AIプロファイルは、Select AIで使用するAIプロバイダーやモデル、LLMへメタデータを送信するDBオブジェクト(表、ビュー)などを定義するものです。このNL2SQLのデモではLLMを指定し、埋め込みモデルは設定しません。 AIプロファイルの生成・登録処理はnl2sql_compare.setup()にあります。以下は初回作成用のAIプロファイル定義です。付録Cで準備済みの場合、プロファイル作成SQLの再実行は不要です。C1の質問から試せます。<OCI_GENAI_COMPARTMENT_OCID>は利用するコンパートメントのOCIDへ置き換えます。付録Cの準備処理でも同じプロファイルを作成します。 BEGIN DBMS_CLOUD_AI.CREATE_PROFILE( profile_name => 'OJ41_NL2SQL_BASELINE', attributes => q'~{ "provider": "oci", "credential_name": "OCI$RESOURCE_PRINCIPAL", "region": "us-chicago-1", "model": "xai.grok-4.3", "oci_compartment_id": "<OCI_GENAI_COMPARTMENT_OCID>", "temperature": 0, "max_tokens": 1600, "object_list": [ { "owner": "ORAJAM41USER", "name": "OJ41_BULK_PARTS" }, { "owner": "ORAJAM41USER", "name": "OJ41_RUN" }, { "owner": "ORAJAM41USER", "name": "OJ41_VISIBLE_CHUNKS" }, { "owner": "ORAJAM41USER", "name": "OJ41_VISIBLE_CONTRACTS" }, { "owner": "ORAJAM41USER", "name": "OJ41_VISIBLE_DEVICES" }, { "owner": "ORAJAM41USER", "name": "OJ41_VISIBLE_KNOWLEDGE" } ], "object_list_mode": "all", "enforce_object_list": true, "comments": false, "annotations": false }~'); END; / AI プロファイルを作成したらいよいよ Select AI による NL2SQL の実行です。 DBMS_CLOUD_AI.GENERATE() 関数の action に showsql を指定すると LLM を使って SQL を生成します。 :::note 上の Select AI の紹介の中にある select ai showsql 質問文 の構文を使う場合は、事前にDBMS_CLOUD_AI.SET_PROFILE() プロシージャで DBセッションに AIプロファイルを設定する必要がありますが、DBMS_CLOUD_AI.GENERATE() 関数は、引数として profile_name を取りますので事前の SET_PROFILE によるセッションへの設定は不要です。AIプロファイル自体は作成しておく必要があります。Database Actions や Oracle APEX のようなステートレスな環境でも、呼び出しごとに使用するプロファイルを指定できます。 ただし、今回のチケットコンテキストはDBセッションに保持されます。profile_name の指定で、この状態まで引き継がれるわけではありません。チケットの設定と、その状態を参照する照会は同じDBセッションで実行してください。Database Actionsでは、チケット設定・照会・チケット解除をまとめて1回のスクリプトとして実行します。 ::: SELECT DBMS_CLOUD_AI.GENERATE( prompt=>'この受付案件の顧客について、基準日時点で現地保守の対象となるサーバーの保守登録番号を昇順で教えてください。', profile_name=>'OJ41_NL2SQL_BASELINE', action=>'showsql') AS generated_sql FROM dual; <details> <summary>実行結果例:チケットと顧客の対応を読み取れず、SQLを生成できなかった</summary> Sorry, unfortunately a valid SELECT statement could not be generated for your natural language prompt with the restriction of enforcing the use of object list. Here is some more information to help you further: The provided tables do not contain any inf