Amazon S3 Vectors vs. OpenSearch Serverless vs. pgvector for RAG: Cost Floors, Query Bills and Tenant Isolation

For two years the default answer to “where do the embeddings go” on AWS was OpenSearch Serverless, with pgvector on Aurora for teams that wanted everything in PostgreSQL. Both are good engines. Both also carried a monthly floor that made small and multi-tenant retrieval-augmented generation (RAG) workloads expensive before they served a single query.

Two releases changed that arithmetic. Amazon S3 Vectors became generally available in December 2025 with no compute to provision at all. Then, on 28 May 2026, AWS shipped a rebuilt OpenSearch Serverless that scales to zero when idle. Add Aurora Serverless v2’s automatic pause, and all three options can now cost close to nothing at rest. They get there by very different routes, and they isolate tenants in very different ways.

This article compares the three on the two questions that decide most designs: what the bill looks like at different workload shapes, and where the tenant boundary sits. The cost model is included and is checked against AWS’s own worked examples. The capacity estimates for OpenSearch and Aurora are marked as estimates.

Three stores, three billing models

Amazon S3 VectorsOpenSearch ServerlessAurora PostgreSQL with pgvector
You pay forStored GB, uploaded GB, query requests, data processed per queryOpenSearch Compute Units (OCUs) per hour, plus stored GBAurora Capacity Units (ACUs) per hour, stored GB, and I/O on Aurora Standard
Published rates, US East (N. Virginia)$0.06 per GB-month, $0.20 per GB uploaded, $2.50 per million queries, $0.004 to $0.0004 per TB processed$0.24 per OCU-hour and $0.02 per GB-month in AWS’s pricing example$0.12 per ACU-hour, $0.10 per GB-month, $0.20 per million I/Os
Cost at restStorage onlyClassic: at least 2 OCUs with standby, 1 without. Next generation: storage only after 10 idle minutesStorage only when minimum capacity is 0 and the instance has paused
First query after idleUnder one second, by AWS’s descriptionAbout 10 seconds on next generation after scaling to zeroUp to 15 seconds to resume
What scales the billSize of the index each query touchesMemory needed to hold the index, and query loadMemory needed to hold the index, and query load
ℹ️
TWO OPENSEARCH SERVERLESS GENERATIONS EXIST

The next-generation collections announced on 28 May 2026 are created through a collection group and are separate from classic collections, which continue to run and continue to bill their minimum. Anything deployed before that date, and any infrastructure template written before it, is classic unless you changed it. Check which one you are paying for.

How S3 Vectors charges for a query

S3 Vectors has no index to keep in memory, so there is no capacity unit. What it meters instead is the data a query has to process, and the definition is precise: the number of vectors in the index queried, multiplied by the average size of a vector, its key and its filterable metadata. Non-filterable metadata is excluded. The rate falls in three tiers, by position within the index: $0.004 per TB for the first 100,000 vectors, $0.002 per TB up to 10 million, and $0.0004 per TB beyond that.

Two consequences follow, and neither is obvious from the headline prices.

  • Query cost grows with index size. A query against a 10-million-vector index processes forty times the data of a query against a 250,000-vector index. The same corpus split into many indexes is cheaper to query than one large index.
  • Metadata placement is a pricing decision. The chunk text you return to the model belongs in non-filterable metadata. It is stored and returned, but it is not counted in the data processed by every query.

AWS’s own first pricing example makes the point without stating it. Ten million vectors, a million queries a month, $11.38. The example quietly assumes forty indexes of 250,000 vectors, one per customer. Put the same ten million vectors in a single index and the query-processing line alone rises from $3.37 to $97.26.

A cost model you can check

The S3 Vectors function below implements the billing rules exactly, using binary units as AWS does. The OpenSearch and Aurora functions are a different kind of thing: capacity estimates built on stated sizing assumptions, because their bills depend on how much memory the index needs.

"""vector_cost_model.py - monthly cost models, US East (N. Virginia)."""
from dataclasses import dataclass
from math import ceil

KIB, GIB, TIB = 1024, 1024**3, 1024**4
HOURS_PER_MONTH = 730


@dataclass(frozen=True)
class Workload:
    indexes: int                     # one per tenant in a siloed design; 1 for a pooled design
    vectors_per_index: int
    dimensions: int = 1024
    key_bytes: int = 174             # 0.17 KB, as in the AWS pricing examples
    filterable_bytes: int = 1024
    non_filterable_bytes: int = 1024
    queries_per_month: int = 1_000_000
    top_k: int = 10
    monthly_write_fraction: float = 1 / 6      # share of the corpus re-embedded each month
    active_hours: float = HOURS_PER_MONTH      # hours in which any query or write arrives

    @property
    def vectors(self) -> int:
        return self.indexes * self.vectors_per_index

    @property
    def vector_bytes(self) -> int:
        return 4 * self.dimensions             # float32

    @property
    def stored_bytes_per_vector(self) -> int:
        return self.vector_bytes + self.key_bytes + self.filterable_bytes + self.non_filterable_bytes


# ---------------------------------------------------------------- Amazon S3 Vectors (exact)
S3V_STORAGE_GB, S3V_PUT_GB, S3V_QUERY_PER_M, S3V_RETURN_GB = 0.06, 0.20, 2.50, 0.01
S3V_TIERS = ((100_000, 0.004), (9_900_000, 0.002), (float("inf"), 0.0004))    # vectors in tier, $ per TB
S3V_FREE_RETURN_BYTES, S3V_MIN_RESULT_BYTES = 500 * KIB, 256


def s3_vectors(w: Workload) -> dict[str, float]:
    stored_gb = w.vectors * w.stored_bytes_per_vector / GIB
    # Query processing is billed on the size of the index a query runs against, not on the corpus.
    processed = w.vector_bytes + w.key_bytes + w.filterable_bytes        # non-filterable metadata is excluded
    remaining, processing = w.vectors_per_index, 0.0
    for tier_vectors, per_tb in S3V_TIERS:
        in_tier = min(remaining, tier_vectors)
        processing += in_tier * processed * w.queries_per_month / TIB * per_tb
        remaining -= in_tier
        if remaining <= 0:
            break
    result_bytes = max(w.key_bytes + w.filterable_bytes + w.non_filterable_bytes, S3V_MIN_RESULT_BYTES)
    billable_return = max(w.top_k * result_bytes - S3V_FREE_RETURN_BYTES, 0)
    return {
        "storage": stored_gb * S3V_STORAGE_GB,
        "writes": stored_gb * w.monthly_write_fraction * S3V_PUT_GB,
        "query_processing": processing,
        "query_requests": w.queries_per_month / 1e6 * S3V_QUERY_PER_M,
        "data_returned": billable_return * w.queries_per_month / GIB * S3V_RETURN_GB,
    }


# ---------------------------------------------------------------- OpenSearch Serverless (estimate)
OCU_HOUR, OSS_STORAGE_GB, OCU_RAM_BYTES, HNSW_M = 0.24, 0.02, 6 * GIB, 16


def hnsw_memory_bytes(w: Workload) -> float:
    """OpenSearch sizing rule for full-precision HNSW: 1.1 * (4 * d + 8 * m) bytes per vector."""
    return 1.1 * (4 * w.dimensions + 8 * HNSW_M) * w.vectors


def _half_units(amount: float) -> float:
    """Capacity is granted in half units at the low end, whole units above that."""
    return 0.5 if amount <= 0.5 else float(ceil(amount))


def opensearch_serverless(w: Workload, *, next_gen: bool, standby: bool = True,
                          compression: float = 1.0) -> dict[str, float]:
    copies = 2 if standby else 1
    search_ocus = _half_units(hnsw_memory_bytes(w) / compression / OCU_RAM_BYTES) * copies
    indexing_ocus = 0.5 * copies
    # Classic bills its minimum around the clock. Next generation bills only hours with activity.
    hours = w.active_hours if next_gen else HOURS_PER_MONTH
    return {
        "compute": (search_ocus + indexing_ocus) * hours * OCU_HOUR,
        "storage": w.vectors * w.stored_bytes_per_vector / GIB * OSS_STORAGE_GB,
    }


# ---------------------------------------------------------------- Aurora Serverless v2 + pgvector (estimate)
ACU_HOUR, AURORA_STORAGE_GB, ACU_RAM_BYTES = 0.12, 0.10, 2 * GIB


def aurora_pgvector(w: Workload, *, auto_pause: bool, min_acu: float = 0.5,
                    compression: float = 1.0) -> dict[str, float]:
    index_bytes = w.vectors * (w.vector_bytes / compression + 8 * HNSW_M * 2)   # vectors plus graph links
    table_bytes = w.vectors * w.stored_bytes_per_vector
    acus = max(_half_units(index_bytes / ACU_RAM_BYTES), min_acu)        # keep the HNSW index in memory
    idle_hours = HOURS_PER_MONTH - w.active_hours
    idle_acu = 0 if auto_pause else min_acu
    return {
        "compute": (acus * w.active_hours + idle_acu * idle_hours) * ACU_HOUR,
        "storage": (index_bytes + table_bytes) / GIB * AURORA_STORAGE_GB,   # Aurora Standard; I/O charged separately
    }
💡
HOW THIS WAS CHECKED

The S3 Vectors function reproduces both worked examples on the AWS pricing page: $11.36 against AWS’s $11.38, and $1,320.34 against $1,320.47. The differences come from AWS rounding gigabytes before multiplying. The classic OpenSearch floor reproduces the documented 2-OCU minimum, $350.40 a month. The remaining OpenSearch and Aurora figures are not checked against a bill.

Three workload shapes

All three scenarios use 1024-dimension vectors with about 2 KB of metadata each, a sixth of the corpus re-embedded every month, and ten results per query.

Table of estimated monthly cost for Amazon S3 Vectors, OpenSearch Serverless classic and next generation, and Aurora pgvector with and without automatic pause, across a pilot, a siloed multi-tenant and a pooled workload.
Estimated monthly cost at three workload shapes. Only the S3 Vectors row changes between B and C.
ConfigurationA. Pilot: 100K vectors, 20K queries, 60 active hoursB. Siloed SaaS: 40 tenants of 250K, 1M queries, 220 active hoursC. Pooled: one index of 10M, 1M queries, 220 active hours
S3 Vectors$0.14$11.36$105.25
OpenSearch Serverless classic, with standby$350.41$2,979.58$2,979.58
OpenSearch Serverless next generation$28.81$898.78$898.78
Aurora pgvector, minimum 0.5 ACU$43.90$594.94$594.94
Aurora pgvector, automatic pause$3.70$564.34$564.34

Three things stand out.

  • At pilot scale the floor is the whole bill. A classic OpenSearch Serverless collection costs $350 a month to hold 100,000 vectors that S3 Vectors stores and serves for fourteen cents. Next-generation collections and a paused Aurora instance close most of that gap.
  • At ten million vectors the memory is the bill. A full-precision HNSW index of this size needs about 43 GiB of memory. On the stated assumptions that is eight OCUs per copy or 21 ACUs, for as many hours as queries arrive. Scaling to zero helps only for the hours nobody is searching.
  • S3 Vectors is the only store whose bill depends on how you partition. Scenarios B and C hold the same data and serve the same queries. Splitting by tenant cuts the S3 Vectors bill by a factor of nine and leaves the other two unchanged in this model.
⚠️
TREAT THE OPENSEARCH AND AURORA ROWS AS PLANNING NUMBERS

They assume the whole index is held in memory at full precision, 6 GiB of memory per OCU and 2 GiB per ACU, and they ignore query CPU and Aurora I/O charges. Half-precision vectors roughly halve the compute: $476 and $298 in scenario B. Stronger quantisation and disk-based search modes reduce it further at some cost in recall. The next-generation OCU rate was not on the pages I read, so the model uses the classic $0.24. Replace it before you quote these figures to anyone.

What the low price gives up

S3 Vectors is cheap because it is an object store with a vector index, not a search engine or a database. The trade is explicit.

CapabilityS3 VectorsOpenSearch ServerlessAurora pgvector
Typical query latencyAbout 100 ms for frequent queries, under a second for infrequent onesMilliseconds to tens of milliseconds when warmMilliseconds to tens of milliseconds when the index is in memory
Keyword and hybrid searchNoYes, lexical and vector in one queryPossible with full-text search and your own ranking
FilteringMetadata filters, up to 2 KB of filterable metadata per vectorFull query DSLAny SQL predicate, joins included
Scale per indexAbout 2 billion vectors, 1 to 4,096 dimensionsBounded by OCU limits on the collectionBounded by instance memory. HNSW on vector supports up to 2,000 dimensions
Results per queryUp to 100 at general availabilityConfigurableAny LIMIT
Transactions with business dataNoNoYes, in the same commit
Bedrock Knowledge BasesSupportedSupportedSupported

For a chat assistant, where the language model takes seconds to answer, 100 ms of retrieval is invisible. For search-as-you-type, or a pipeline that issues dozens of retrievals per request, it is not. And if relevance depends on exact terms such as product codes, drug names or error identifiers, the absence of keyword search matters more than any latency figure.

Where the tenant boundary sits

Cost and isolation turn out to be the same decision in two of the three stores.

Three cards comparing tenant isolation: index per tenant on Amazon S3 Vectors, collection per tenant on OpenSearch Serverless, and row-level security on Aurora pgvector, with enforcement, ceiling, idle cost and offboarding for each.
The isolation unit that is cheapest to operate correctly in each store.

S3 Vectors: one index per tenant. An index has its own ARN, so IAM can grant a principal access to exactly one tenant’s vectors, and a bucket holds up to 10,000 indexes. Because query cost follows index size, the siloed design is also the cheap one. The application never passes a tenant filter. It addresses a different index.

"""s3vectors_tenant.py - one vector index per tenant inside one vector bucket (excerpt)."""
import re
from typing import Any

import boto3
from botocore.config import Config

BUCKET = "rag-vectors-prod"
TENANT_ID = re.compile(r"[a-z0-9][a-z0-9-]{1,40}")

_client = boto3.client(
    "s3vectors",
    config=Config(retries={"max_attempts": 8, "mode": "adaptive"}, connect_timeout=3, read_timeout=10),
)


def index_name(tenant_id: str) -> str:
    """The tenant id comes from the caller's verified identity, never from request text."""
    if not TENANT_ID.fullmatch(tenant_id):
        raise ValueError("invalid tenant id")
    return f"tenant-{tenant_id}"


def search(tenant_id: str, embedding: list[float], top_k: int = 8,
           doc_id: str | None = None, client: Any = _client) -> list[dict]:
    request: dict[str, Any] = {
        "vectorBucketName": BUCKET,
        "indexName": index_name(tenant_id),
        "queryVector": {"float32": embedding},
        "topK": top_k,
        "returnMetadata": True,       # needs s3vectors:GetVectors as well as s3vectors:QueryVectors
        "returnDistance": True,
    }
    if doc_id:
        request["filter"] = {"doc_id": {"$eq": doc_id}}
    return client.query_vectors(**request)["vectors"]


def tenant_policy(account_id: str, region: str) -> dict:
    """Attach to the role the application assumes with a TenantId session tag.
    One policy serves every tenant. Verify the tag substitution in your account before relying on it."""
    return {
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Action": ["s3vectors:QueryVectors", "s3vectors:GetVectors", "s3vectors:PutVectors",
                       "s3vectors:DeleteVectors"],
            "Resource": f"arn:aws:s3vectors:{region}:{account_id}:bucket/{BUCKET}"
                        "/index/tenant-${aws:PrincipalTag/TenantId}",
        }],
    }
%%{init: {'theme':'base','themeVariables':{'actorBkg':'#FFF3E0','actorBorder':'#FF9900','actorTextColor':'#232F3E','signalColor':'#0073BB','signalTextColor':'#0F172A','noteBkgColor':'#FFF8E7','noteBorderColor':'#FF9900','noteTextColor':'#232F3E','labelBoxBkgColor':'#FFF3E0','labelBoxBorderColor':'#FF9900','labelTextColor':'#232F3E','loopTextColor':'#232F3E','activationBkgColor':'#EBF8FF','activationBorderColor':'#0073BB','lineColor':'#232F3E','textColor':'#232F3E'}}}%%
sequenceDiagram
    participant A as RAG service
    participant T as AWS STS
    participant V as S3 Vectors
    participant M as Bedrock model
    A->>T: AssumeRole, session tag TenantId=acme
    T-->>A: Credentials scoped by tag
    A->>V: QueryVectors on index tenant-acme
    V-->>A: Top matches + chunk text
    A->>M: Prompt with retrieved context
    M-->>A: Answer
    Note over A,V: A request for tenant-globex
is denied by IAM, not by app code

OpenSearch Serverless: one collection per tenant. Under classic pricing this was unaffordable beyond a handful of tenants, because every collection carried the minimum. On next-generation collection groups an idle tenant costs storage only, and data access policies with wildcard patterns keep the policy count manageable. The price is a cold start: AWS describes the first request after scaling to zero as taking about 10 seconds. Setting a minimum above zero removes the wait and restores a floor.

Aurora pgvector: row-level security. The natural model in PostgreSQL is one table with a tenant column and a policy the database enforces on every statement.

-- pgvector_rls.sql - pooled multi-tenancy: one table, row-level security.
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE chunks (
    id         bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    tenant_id  text        NOT NULL,
    doc_id     text        NOT NULL,
    content    text        NOT NULL,
    embedding  vector(1024) NOT NULL
);

CREATE INDEX chunks_tenant_idx ON chunks (tenant_id);
CREATE INDEX chunks_embedding_idx ON chunks USING hnsw (embedding vector_cosine_ops)
    WITH (m = 16, ef_construction = 64);

-- Every query is filtered by the tenant held in the session, whatever SQL the application sends.
ALTER TABLE chunks ENABLE ROW LEVEL SECURITY;
ALTER TABLE chunks FORCE ROW LEVEL SECURITY;          -- applies to the table owner as well

CREATE POLICY tenant_isolation ON chunks
    USING      (tenant_id = current_setting('app.tenant_id', true))
    WITH CHECK (tenant_id = current_setting('app.tenant_id', true));

-- The application connects as a role that cannot bypass the policy.
CREATE ROLE rag_app NOLOGIN NOBYPASSRLS;
GRANT SELECT, INSERT, DELETE ON chunks TO rag_app;

The application sets the tenant inside each transaction with SELECT set_config('app.tenant_id', $1, true), so the value cannot leak to the next user of a pooled connection. In the test, each tenant’s similarity search returned only its own rows, a session with no tenant set returned nothing, and an insert carrying another tenant’s id was rejected.

⚠️
TWO THINGS THE TESTS DO NOT PROVE

The IAM policy that substitutes a session tag into the index ARN was not run in an AWS account. The S3 Vectors requests were validated offline against the SDK service model, which says nothing about authorization. Confirm that a session tagged for one tenant is denied on another tenant’s index. And row-level security filters after the HNSW index has chosen its candidates: a small tenant in a large shared index can get fewer rows than it asked for. pgvector 0.8.0, available on Aurora since April 2025, addresses this with iterative index scans (SET hnsw.iterative_scan = strict_order). Measure recall per tenant, not only in aggregate.

Choosing between them

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FFF3E0','primaryTextColor':'#232F3E','primaryBorderColor':'#FF9900','lineColor':'#232F3E','clusterBkg':'#F8FAFC','clusterBorder':'#CBD5E1','edgeLabelBackground':'#FFFFFF','nodeTextColor':'#232F3E'}}}%%
flowchart TD
    Q1{Need keyword or hybrid search,
or retrieval in single-digit ms?} Q1 -- "Yes" --> OS[OpenSearch Serverless
next generation] Q1 -- "No" --> Q2{Must vectors change in the same
transaction as business rows?} Q2 -- "Yes" --> PG[Aurora PostgreSQL
with pgvector] Q2 -- "No" --> Q3{Many tenants, or queries
that arrive in bursts?} Q3 -- "Yes" --> S3[S3 Vectors
one index per tenant] Q3 -- "No" --> Q4{Already run Aurora
with spare capacity?} Q4 -- "Yes" --> PG Q4 -- "No" --> S3 class Q1,Q2,Q3,Q4 edge class OS mesh class PG compute class S3 store classDef compute fill:#FFF3E0,stroke:#FF9900,stroke-width:2px,color:#232F3E classDef edge fill:#EBF8FF,stroke:#0073BB,stroke-width:2px,color:#004C74 classDef store fill:#F0FFF4,stroke:#1D8102,stroke-width:2px,color:#145202 classDef alert fill:#FEF2F2,stroke:#D13212,stroke-width:2px,color:#991B1B classDef mesh fill:#F3E8FF,stroke:#7C3AED,stroke-width:2px,color:#4C1D95
  • Start with S3 Vectors for document question-answering, internal assistants and multi-tenant SaaS where a retrieval takes place once per user turn. The cost floor is zero and the isolation model is IAM.
  • Choose OpenSearch Serverless when relevance needs lexical matching alongside vectors, when latency budgets are tight, or when the same engine already serves search. Use next-generation collections for anything new.
  • Choose pgvector when embeddings are an attribute of rows you already keep in PostgreSQL and must stay consistent with them, or when retrieval needs joins and predicates that metadata filters cannot express.
  • Combine them when the corpus has a hot head and a long tail. The S3 Vectors announcement describes OpenSearch managing vector storage in S3 for exactly this split.

Running it in production

  • Batch writes to S3 Vectors. A PutVectors call accepts up to 500 vectors and each call carries a minimum charge. Single-vector writes multiply the upload bill.
  • Plan for the first query. All three scale-to-zero options answer the first request slowly: under a second, about 10 seconds, or up to 15 seconds. Decide per workload whether to keep capacity warm, and set client timeouts above the resume time.
  • Know what blocks an Aurora pause. Open connections, RDS Proxy and logical replication all keep the instance awake. A connection pool that never closes its connections quietly turns automatic pause into a 0.5 ACU floor.
  • Tag by tenant. Per-tenant indexes and collections make cost attribution possible. Without tags the bill is one line.
  • Keep the embedding model in the index name or metadata. Re-embedding with a new model means a new index. Dual-write and cut over per tenant.
  • Measure recall with your own questions. Approximate search, filters and quantisation all trade recall for cost. Keep a fixed evaluation set per tenant and run it whenever the configuration changes.
⚖️
EMBEDDINGS OF PERSONAL DATA ARE PERSONAL DATA

A vector derived from a document about a person, stored next to the chunk text, falls under GDPR in the same way as the source. A tenant boundary that maps to a deletable unit, an index or a collection, makes erasure and offboarding one auditable operation. In a pooled table it is a filtered delete followed by vacuum. AWS notes that deleted S3 vectors disappear from query results at once, while their storage can take up to a day to be reclaimed. For health or other special-category data, use a customer-managed KMS key and confirm that the retrieval path cannot cross tenants before any clinical content is indexed.

Key takeaways

  • By mid-2026 all three AWS vector stores can cost near zero at rest. They differ in what happens once queries arrive.
  • S3 Vectors bills each query on the size of the index it touches. One index per tenant is both the isolation model and the cheapest layout.
  • For OpenSearch Serverless and Aurora, memory to hold the index is the dominant cost at scale. Quantisation is the main lever.
  • Classic OpenSearch Serverless collections still carry a two-OCU minimum. New work belongs on next-generation collections.
  • Choose on capability first: hybrid search and latency point to OpenSearch, transactional consistency to pgvector, and everything else to S3 Vectors.

If you have production bills for any of these three at ten million vectors or more, I would like to compare them with the estimates here. Leave a comment below.

📝
UPDATE, NOVEMBER 2026

The rates in this article were read from the AWS pricing pages in November 2026 and matched against AWS’s worked examples. I could not confirm that every line was identical on 30 June. S3 Vectors limits have since been raised: the documentation now lists up to 10,000 results per query and an enhanced query mode. Check the current limits and pricing pages before committing to a design.

Glossary

RAG (retrieval-augmented generation)
Fetching relevant passages from a store and adding them to a model prompt so that answers are grounded in your own data.
Embedding
A list of numbers representing the meaning of a piece of text. Similar texts have nearby embeddings.
Vector index
A structure that finds the nearest embeddings to a query without comparing against every stored vector.
HNSW
Hierarchical Navigable Small World. A graph-based approximate nearest-neighbour index, fast when held in memory.
Quantisation
Storing vectors at lower precision to save memory, at some cost in recall.
Recall
The share of the true nearest neighbours that an approximate search returns.
OCU (OpenSearch Compute Unit)
The capacity unit OpenSearch Serverless bills by the hour for indexing and search.
ACU (Aurora Capacity Unit)
The capacity unit Aurora Serverless v2 bills by the hour, roughly 2 GiB of memory with matching CPU.
Vector bucket
The S3 Vectors container that holds vector indexes.
Filterable metadata
Key-value data stored with a vector that queries can filter on. In S3 Vectors it counts towards query data processed.
Siloed and pooled tenancy
Siloed gives each tenant its own resource. Pooled shares one resource and separates tenants by policy or filter.
Row-level security
A PostgreSQL feature that applies a policy to every query on a table, restricting which rows a session can see or change.
Hybrid search
Combining keyword matching and vector similarity in one ranked result.

References & Further Reading


Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.