[{"data":1,"prerenderedAt":738},["ShallowReactive",2],{"blog-pgvector-en":3},{"slug":4,"published":5,"minutes":6,"category":7,"tags":8,"keywords":14,"about":21,"sources":27,"cover":42,"og":43,"expertise":44,"locales":45,"lang":46,"title":49,"description":50,"coverAlt":51,"metaTitle":52,"takeaways":53,"faq":59,"toc":72,"blocks":97,"others":486},"pgvector","2026-09-21",10,"rag",[9,10,11,12,13],"Vector search","Postgres","HNSW","RAG","Quantisation",[4,15,16,17,18,19,20],"pgvector vs qdrant","postgres vector search","hnsw index postgres","iterative index scans","binary quantization postgres","vector database postgres",[22,24],{"name":4,"url":23},"https:\u002F\u002Fgithub.com\u002Fpgvector\u002Fpgvector",{"name":25,"url":26},"PostgreSQL","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPostgreSQL",[28,30,33,36,39],{"title":29,"url":23},"pgvector README",{"title":31,"url":32},"pgvector changelog","https:\u002F\u002Fgithub.com\u002Fpgvector\u002Fpgvector\u002Fblob\u002Fmaster\u002FCHANGELOG.md",{"title":34,"url":35},"PostgreSQL news: pgvector 0.8.2 released","https:\u002F\u002Fwww.postgresql.org\u002Fabout\u002Fnews\u002Fpgvector-082-released-3245\u002F",{"title":37,"url":38},"AWS: Scale pgvector with binary quantization","https:\u002F\u002Faws.amazon.com\u002Fblogs\u002Fdatabase\u002Fscale-pgvector-with-binary-quantization-on-amazon-aurora-postgresql\u002F",{"title":40,"url":41},"pgvector licence","https:\u002F\u002Fgithub.com\u002Fpgvector\u002Fpgvector\u002Fblob\u002Fmaster\u002FLICENSE","\u002Fimages\u002Fblog\u002Fpgvector\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fpgvector\u002Fog.jpg","ai-engineer",[46,47,48],"en","de","hu","pgvector, reviewed: the vector database you do not have to run","A review of pgvector 0.8.7: iterative scans for filtered search, HNSW and IVFFlat, binary quantisation at 100M vectors, and the CVE that made index builds a patch item.","An upright cylinder with three stacked bars, a square module docked left and a shield.","pgvector: vector search inside Postgres · Balázs Csorba",[54,55,56,57,58],"pgvector is a PostgreSQL extension under the PostgreSQL licence, so vectors live in ordinary tables and tenant filters, JOINs and cascading deletes stay transactional.","Iterative index scans, added in 0.8.0, are the fix for filtered search: without them a filter matching 10% of rows at the default ef_search of 40 returns about four rows.","AWS measured a 367 GB HNSW index for 100M vectors at 768 dimensions against a 38 GB binary-quantised index that built in 1.1 hours instead of 16.1.","CVE-2026-3172, fixed in 0.8.2 in February 2026, was a buffer overflow in parallel HNSW index builds that could leak data from other relations; the fix needs no reindex.","The ceiling is memory rather than the API: once the index stops fitting shared_buffers the choices are halfvec, binary quantisation, partitioning or a second system.",[60,63,66,69],{"q":61,"a":62},"Is pgvector free to use?","Yes. It is released under the PostgreSQL licence with no fee, no open-core split and no paid tier, and it is preinstalled by an increasing number of hosted Postgres providers. Check which version they ship: 0.8.0 or later is needed for iterative index scans.",{"q":64,"a":65},"When should I use HNSW instead of IVFFlat?","HNSW gives a better speed-recall trade-off, can be created on an empty table because it has no training step, and is slower to build and hungrier for memory. IVFFlat builds faster and needs data present first; the README suggests lists = rows \u002F 1000 up to one million rows, sqrt(rows) above that, and probes starting at sqrt(lists).",{"q":67,"a":68},"Does pgvector work with a WHERE clause?","Yes, but with an approximate index the filter runs after the index scan, so a selective condition can return fewer rows than the LIMIT asks for. The documented answers are a B-tree on the filter column, iterative index scans with hnsw.iterative_scan, partial indexes per value, and list partitioning for many distinct values.",{"q":70,"a":71},"How many vectors can pgvector handle?","A single table is limited by PostgreSQL's 32 TB relation limit and by how much of the index fits in memory; AWS measured 367 GB of index for 100 million 768-dimensional vectors and recommends partitioning at billion scale. Beyond that the README points at replicas, Citus, PgDog or list partitioning rather than a built-in sharding layer.",[73,76,79,82,85,88,91,94],{"id":74,"title":75},"what-it-is","What it is",{"id":77,"title":78},"how-it-works","How it works",{"id":80,"title":81},"filtered-search","Filtered search",{"id":83,"title":84},"getting-started","Getting started",{"id":86,"title":87},"performance","Performance",{"id":89,"title":90},"where-it-shingles","Where it falls short",{"id":92,"title":93},"verdict","Verdict",{"id":95,"title":96},"sources","Sources",[98,102,105,108,111,183,184,195,201,212,213,216,250,265,266,269,271,278,292,293,296,348,351,357,383,384,387,431,437,438,441,456,462,463],{"type":99,"content":100},"paragraph",[101],"pgvector is a PostgreSQL extension that puts vectors in an ordinary table and searches them with ordinary SQL. It is not a vector database with a query language bolted on: it adds four column types, six distance operators and two index types to a database most teams already operate, under the PostgreSQL licence, which is about as permissive as licensing gets. The position taken here is that this is the right default for almost every retrieval workload up to tens of millions of vectors, and that a team standing up a dedicated vector database at that size is buying operational burden rather than capability.",{"type":99,"content":103},[104],"It competes with Qdrant, Weaviate, Chroma and the fully managed vector services, and with every hosted Postgres that now ships the extension by default. What it removes is a whole class of infrastructure: no second service to run, no second wire protocol to authenticate, no second backup schedule, no consistency gap between the rows and the embeddings that describe them. What it keeps is every Postgres constraint, one node's memory, one node's vacuum, one node's write throughput, and those become the design inputs the moment the index stops fitting in RAM.",{"type":106,"level":107,"id":74,"text":75},"heading",2,{"type":99,"content":109},[110],"The first release, 0.1.0, was published on 20 April 2021, and the current release is 0.8.7, published on 1 October 2026; the repository showed 23,300 stars and 1,300 forks when checked. It supports PostgreSQL 13 and later, ships as Docker image, PGXN, APT, Yum, Homebrew and conda-forge package, and comes preinstalled on a growing list of hosted providers, which matters because a managed provider stuck on an old version is the most common way a team ends up without a security fix it believes it has.",{"type":112,"ordered":113,"items":114},"list",false,[115,122,127,146,155,181],[116,117,121],"Licence: ",{"tag":118,"children":119},"strong",[120],"the PostgreSQL licence",", the same permissive text PostgreSQL itself uses. No open core, no commercial tier, no feature gated behind a paid plan.",[123,124,126],"Version 0.8.7 of 1 October 2026; the 0.8 line has carried ",{"tag":118,"children":125},[18]," since 0.8.0 in October 2024, which is the feature that made filtered search predictable.",[128,129,133,134,137,138,141,142,145],"Four types: ",{"tag":130,"children":131},"code",[132],"vector"," at 4 bytes per dimension, ",{"tag":130,"children":135},[136],"halfvec"," at 2, ",{"tag":130,"children":139},[140],"bit"," at one bit per dimension, and ",{"tag":130,"children":143},[144],"sparsevec"," for sparse vectors with up to 1,000 non-zero elements.",[147,148,150,151,154],"Two index types: ",{"tag":118,"children":149},[11]," for the best speed-recall trade-off and no training step, ",{"tag":118,"children":152},[153],"IVFFlat"," for faster builds and a smaller memory footprint.",[156,157,160,161,164,165,168,169,172,173,176,177,180],"Six operators usable directly in ORDER BY: L2 (",{"tag":130,"children":158},[159],"\u003C->","), inner product (",{"tag":130,"children":162},[163],"\u003C#>","), cosine (",{"tag":130,"children":166},[167],"\u003C=>","), L1 (",{"tag":130,"children":170},[171],"\u003C+>","), Hamming (",{"tag":130,"children":174},[175],"\u003C~>",") and Jaccard (",{"tag":130,"children":178},[179],"\u003C%>",").",[182],"Storage and access come from Postgres itself: ACID, WAL replication, point-in-time recovery, JOINs and row-level security on the same table as the embeddings.",{"type":106,"level":107,"id":77,"text":78},{"type":99,"content":185},[186,187,190,191,194],"Without an index, a vector query is a sequential scan with an ORDER BY over the distance function: exact results, perfect recall, and a cost that tracks the table. An approximate index changes that bargain. HNSW builds a multi-layer graph over the vectors and walks it, trading a little recall for a query cost that no longer grows with the table; IVFFlat groups vectors into lists and probes a subset of them. The detail that decides everything is that the planner only reaches for an index when the query looks like ",{"tag":130,"children":188},[189],"ORDER BY embedding \u003C=> $1 LIMIT n",". Write the same query as ",{"tag":130,"children":192},[193],"ORDER BY 1 - (embedding \u003C=> $1) DESC"," and the README states plainly that no index will be used.",{"type":196,"src":197,"alt":198,"wide":199,"caption":200},"image","\u002Fimages\u002Fblog\u002Fpgvector\u002Fdiagram-7.webp","Three execution paths for one vector query A query carrying an ORDER BY over a distance operator and a LIMIT enters at the top and splits three ways. Left, no index: a sequential scan with perfect recall whose cost grows with every row. Middle, HNSW: a walk over a multilayer graph with m set to 16 and ef_search set to 40 by default, where any WHERE clause is applied only after the index scan has produced its candidates. Right, IVFFlat: vectors grouped into lists and only the closest lists probed, built after the data exists and tuned through ivfflat.probes, at a lower speed-recall trade-off. A band below: iterative index scans, added in 0.8.0, keep walking while the filter removes rows, in strict_order or relaxed_order, bounded by hnsw.max_scan_tuples with a default of 20,000.",true,"The filter is applied after the approximate index has done its work, which is why a selective WHERE clause and an approximate index disagree until the scan is allowed to continue.",{"type":99,"content":202},[203,204,207,208,211],"The second detail is where the ",{"tag":130,"children":205},[206],"WHERE"," clause lands. An approximate index produces candidates and the filter is applied to them afterwards, so selectivity and recall interact: with the default ",{"tag":130,"children":209},[210],"hnsw.ef_search"," of 40 and a condition matching 10% of rows, about four rows come back. Nothing is broken, the index simply never saw the rows that were dropped. That behaviour is the most common source of reports claiming the extension returns fewer results, and it has a documented fix rather than a workaround.",{"type":106,"level":107,"id":80,"text":81},{"type":99,"content":214},[215],"Filtering is a first-class problem here rather than an afterthought, and the documentation works through four moves in the order a reviewer would try them. Which one applies depends on how selective the filter is, how much recall the application actually needs, and how many distinct values the filter takes: a tenant id with 50,000 values behaves nothing like a country code with eight.",{"type":112,"ordered":113,"items":217},[218,224,234,248],[219,220,223],"Index the filter column with a plain ",{"tag":118,"children":221},[222],"B-tree first",". When the condition matches a small share of rows this returns exact nearest neighbours without touching an approximate index, and the README names it as the starting point.",[225,226,229,230,233],"If the filter stays broad, turn on iterative index scans with ",{"tag":130,"children":227},[228],"SET hnsw.iterative_scan = relaxed_order",": the graph is walked until the LIMIT is full, and ",{"tag":130,"children":231},[232],"strict_order"," is there when the distance order has to be exact.",[235,236,239,240,243,244,247],"Bound the work. ",{"tag":130,"children":237},[238],"hnsw.max_scan_tuples"," defaults to 20,000 and ",{"tag":130,"children":241},[242],"hnsw.scan_mem_multiplier"," to one multiple of ",{"tag":130,"children":245},[246],"work_mem",", so a selective filter degrades into a bounded scan rather than an open-ended one.",[249],"For many distinct values, use partial indexes per value or list-partition the table. The README also notes that tenants sharing one approximate index affect each other's recall, which is a partitioning argument rather than a tuning argument.",{"type":251,"variant":252,"title":253,"body":254},"callout","note","Recall is the metric nobody measures",[255],[256,257,260,261,264],"The documentation's own method for checking this is to run the same query inside a transaction with ",{"tag":130,"children":258},[259],"enable_indexscan = off"," and compare it against the approximate result. Teams tune ",{"tag":130,"children":262},[263],"ef_search"," for latency and skip the comparison, which is how an index that returns four rows out of ten gets described as fast.",{"type":106,"level":107,"id":83,"text":84},{"type":99,"content":267},[268],"The whole surface is SQL, which is the reason to prefer it over a system with its own API. The snippet below is the shape of a production table: a fixed-dimension column, an exact index on the filter, an approximate index on the vector, and the one setting that decides whether a filtered query comes back short.",{"type":130,"code":270},"CREATE EXTENSION IF NOT EXISTS vector;\n\n-- The dimension is part of the type, so every row has to match it.\nCREATE TABLE chunks (\n  id         bigserial PRIMARY KEY,\n  tenant_id  text       NOT NULL,\n  embedding  vector(1536)\n);\n\n-- Exact index on the filter first: for a selective tenant it answers the\n-- whole query and the approximate index is never consulted.\nCREATE INDEX ON chunks (tenant_id);\n\n-- Bulk load with COPY, then build the approximate index on top of the data.\nCREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops)\n  WITH (m = 16, ef_construction = 64);\n\n-- A filter matching 10% of rows with ef_search = 40 returns about four rows,\n-- so the scan has to be allowed to continue past its first pass.\nSET hnsw.iterative_scan = relaxed_order;\nSET hnsw.ef_search = 100;\n\nSELECT id\nFROM chunks\nWHERE tenant_id = 'acme'\nORDER BY embedding \u003C=> (SELECT embedding FROM chunks WHERE id = 42)\nLIMIT 10;",{"type":99,"content":272},[273,274,277],"Three choices in that snippet are worth defending. The dimension is part of the type, so a row written by a different embedding model fails at ",{"tag":130,"children":275},[276],"INSERT"," instead of at query time. The approximate index is built after the data, because an HNSW graph created on an empty table has nothing to link and would be rebuilt anyway. And the probe vector comes from a subselect, which is the form the planner accepts; the same query with an expression inside the ORDER BY falls back to a sequential scan without warning.",{"type":251,"variant":279,"title":280,"body":281},"warn","Patch before you build an index",[282],[283,284,287,288,291],"CVE-2026-3172, fixed in 0.8.2 on 25 February 2026, was a buffer overflow in parallel HNSW index builds that could leak data from other relations or crash the server. The fix is an extension update, ",{"tag":130,"children":285},[286],"ALTER EXTENSION pgvector UPDATE",", with no reindex; while an upgrade is impossible, ",{"tag":130,"children":289},[290],"max_parallel_maintenance_workers = 0"," for the duration of the build is the documented mitigation. Later releases fixed further buffer overflows in IVFFlat builds, in 0.8.6 and again in 0.8.7 of 1 October 2026, so the version number the managed provider actually ships is worth reading rather than assuming.",{"type":106,"level":107,"id":86,"text":87},{"type":99,"content":294},[295],"Memory is the whole performance story. A vector column costs 4 bytes per dimension plus an 8-byte header, so 1,536 dimensions are about 6 KB per row before any index, and a full-precision HNSW index over 100 million 768-dimensional vectors measured 367 GB in AWS's benchmark, roughly 3.7 GB per million vectors. The alternative types exist to attack exactly that number.",{"type":297,"head":298,"rows":307},"table",[299,301,303,305],[300],"Type",[302],"Bytes per dimension",[304],"Indexable limit",[306],"What it costs you",[308,318,328,338],[309,312,314,316],[310],{"tag":130,"children":311},[132],[313],"4",[315],"2,000 dims",[317],"the baseline; exact search over it is exact recall",[319,322,324,326],[320],{"tag":130,"children":321},[136],[323],"2",[325],"4,000 dims",[327],"half the index, near-zero recall loss in the AWS tests",[329,332,334,336],[330],{"tag":130,"children":331},[140],[333],"1\u002F8",[335],"64,000 dims",[337],"Hamming over sign bits, needs reranking to hold recall",[339,342,344,346],[340],{"tag":130,"children":341},[144],[343],"8 per non-zero",[345],"1,000 non-zero",[347],"sparse embeddings, L2, cosine, inner product and L1",{"type":99,"content":349},[350],"AWS published the clearest public numbers on this, running VectorDBBench v0.3.4 at top_k=100 on Aurora PostgreSQL 18.4 with pgvector 0.8.0. On LAION 100M at 768 dimensions, an r8g.4xlarge with 128 GB held a 367 GB full-precision HNSW index it could not keep in cache: 3.4 queries per second cold at concurrency 10, 3,336 once warm, recall 0.965, 16.1 hours to build. Binary quantisation with reranking cut the index to 38 GB and the build to 1.1 hours, reached 13.5 cold and 895 warm queries per second, and paid for it in recall: 0.931.",{"type":99,"content":352},[353,354,356],"The same benchmark carries the counter-example, which is why its numbers should be read with their methodology. On Cohere 10M, whose 768-dimensional embeddings cluster near zero, binary quantisation needed a 3,000-candidate rerank to reach 0.93 recall and collapsed to 16 queries per second with a p99 of 1,640 ms, while full-precision HNSW on a 384 GB instance delivered 6,930 queries per second at 0.952 recall. Quantisation is distribution-dependent: validate recall on your own embeddings, or take ",{"tag":130,"children":355},[136]," and halve the index instead of guessing.",{"type":112,"ordered":113,"items":358},[359,365,375,381],[360,361,364],"Raise ",{"tag":130,"children":362},[363],"maintenance_work_mem"," before building an HNSW index; Postgres prints a notice when the graph stops fitting, and the README warns against raising it until the server runs out of memory.",[366,367,370,371,374],"Load with ",{"tag":130,"children":368},[369],"COPY"," and index afterwards, and use ",{"tag":130,"children":372},[373],"CREATE INDEX CONCURRENTLY"," in production so the build does not block writes.",[376,377,380],"VACUUM on an HNSW index can take a while; the documented speed-up is ",{"tag":130,"children":378},[379],"REINDEX INDEX CONCURRENTLY"," first, vacuum after.",[382],"Horizontal scale is borrowed rather than built: replication and point-in-time recovery come from the WAL, and the README points at Citus, PgDog or list partitioning for sharding.",{"type":106,"level":107,"id":89,"text":90},{"type":99,"content":385},[386],"The weaknesses are structural rather than unfinished. Everything runs on one Postgres node, so the index, the heap and the buffer cache compete for the same memory, and an index that stops fitting becomes an I\u002FO problem before it becomes a recall problem. Approximate search and selective filters still fight even with iterative scans, because a bounded scan is bounded. Vacuum and index maintenance are the database's chores rather than someone else's. And there is no built-in sharding: horizontal scale means replicas, partitioning or an extension.",{"type":297,"head":388,"rows":397},[389,391,393,395],[390],"Alternative",[392],"Runs as",[394],"Operational surface",[396],"Where it pulls ahead",[398,409,420],[399,403,405,407],[400],{"tag":118,"children":401},[402],"Qdrant",[404],"A separate Rust server, or the vendor cloud",[406],"Another cluster to patch, back up and secure",[408],"Payload filtering and quantisation tuned for recall at scale",[410,414,416,418],[411],{"tag":118,"children":412},[413],"Weaviate",[415],"A separate server with a GraphQL API, or the vendor cloud",[417],"The same again, plus its own module configuration",[419],"Hybrid search and vectorisation configured in one place",[421,425,427,429],[422],{"tag":118,"children":423},[424],"Chroma",[426],"Embedded in the process, or a small standalone server",[428],"Almost none, but no Postgres either",[430],"The shortest path from a prototype to a running system",{"type":99,"content":432},[433,434,436],"The honest boundary: pgvector wins while the vector work is a column of data the team already stores, and starts losing when one query has to hold a large graph, a filtered scan and the rest of the application's working set in the same memory. AWS measured that boundary at 367 GB of index for 100 million vectors and worked around it with quantisation and partitioning. Teams that do not want to own that trade have four exits, ",{"tag":130,"children":435},[136],", binary quantisation with reranking, partitioning by tenant, or a dedicated store, and the first two are cheap enough that they should be tried before the fourth is discussed.",{"type":106,"level":107,"id":92,"text":93},{"type":99,"content":439},[440],"pgvector should be the default answer to where these embeddings go for any team that already runs Postgres, and a dedicated vector database should have to argue its way past it. The extension has the unusual property that its failure modes are the failure modes of a database the team already understands: memory pressure, maintenance windows, one node's write throughput. Choose something else deliberately, at a scale or a latency target that can be named.",{"type":112,"ordered":199,"items":442},[443,445,447,449,454],[444],"Take pgvector when the vectors describe rows the team already stores, and tenant isolation, cascading deletes or a JOIN with the source table have to be transactional.",[446],"Take it when the corpus is up to a few tens of millions of vectors and the filter is selective enough that a B-tree on the filter column carries most of the query.",[448],"Take it when the alternative is a second production system: the extension inherits backup, replication, monitoring and access control that already exist and adds nothing new to operate.",[450,451,453],"Do not take it when a single query has to keep a multi-hundred-gigabyte graph plus the application's working set in memory, unless ",{"tag":130,"children":452},[136]," or binary quantisation has already been measured on the actual embeddings.",[455],"Do not take it when the requirement is sustained multi-node write throughput or low-latency filtered recall across hundreds of millions of vectors; that is partitioning or a purpose-built store, and postponing it costs a migration later.",{"type":457,"content":458},"quote",[459,460,461],"Not all embedding models produce vectors that quantize well. Validate on your data before committing."," ","— AWS Database Blog, 18 August 2026",{"type":106,"level":107,"id":95,"text":96},{"type":112,"ordered":199,"items":464},[465,470,474,478,482],[466],{"tag":467,"href":23,"children":468},"a",[469],"pgvector README: types, indexing, filtering and scaling",[471],{"tag":467,"href":32,"children":472},[473],"pgvector changelog, 0.1.0 through 0.8.7",[475],{"tag":467,"href":35,"children":476},[477],"PostgreSQL news: pgvector 0.8.2 released (CVE-2026-3172)",[479],{"tag":467,"href":38,"children":480},[481],"AWS: Scale pgvector with binary quantization on Aurora PostgreSQL",[483],{"tag":467,"href":41,"children":484},[485],"pgvector licence: the PostgreSQL licence",[487,561,620,677],{"slug":488,"published":489,"minutes":490,"category":7,"tags":491,"keywords":495,"about":508,"sources":518,"cover":555,"og":556,"expertise":44,"locales":557,"lang":46,"title":558,"description":559,"coverAlt":560},"embedding-model-selection-2026","2026-10-17",9,[492,12,493,9,494],"Embeddings","MTEB","Model selection",[496,497,498,499,500,501,502,503,504,505,506,507],"best embedding model 2026","how to choose an embedding model","embedding model comparison","MTEB leaderboard explained","RTEB benchmark","open source embedding model","multilingual embedding model","voyage-4 vs openai embeddings","Qwen3-Embedding","EmbeddingGemma","embedding model for RAG","switching embedding models re-embed",[509,512,515],{"name":510,"url":511},"Word embedding","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWord_embedding",{"name":513,"url":514},"Information retrieval","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FInformation_retrieval",{"name":516,"url":517},"Discounted cumulative gain","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDiscounted_cumulative_gain",[519,522,525,528,531,534,537,540,543,546,549,552],{"title":520,"url":521},"Enevoldsen et al.: MMTEB, Massive Multilingual Text Embedding Benchmark (2025)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2502.13595",{"title":523,"url":524},"Hugging Face: Introducing RTEB, a new standard for retrieval evaluation (Oct 2025)","https:\u002F\u002Fhuggingface.co\u002Fblog\u002Frteb",{"title":526,"url":527},"OpenAI: Vector embeddings guide","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings",{"title":529,"url":530},"OpenAI: API pricing","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fpricing",{"title":532,"url":533},"Voyage AI: The Voyage 4 model family, shared embedding space with MoE architecture (Jan 2026)","https:\u002F\u002Fblog.voyageai.com\u002F2026\u002F01\u002F15\u002Fvoyage-4\u002F",{"title":535,"url":536},"Voyage AI: Text embeddings documentation","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fembeddings",{"title":538,"url":539},"Voyage AI: Pricing","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fpricing",{"title":541,"url":542},"Google: Gemini API embeddings documentation","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fembeddings",{"title":544,"url":545},"Google: Gemini API pricing","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fpricing",{"title":547,"url":548},"Cohere: Embed models documentation","https:\u002F\u002Fdocs.cohere.com\u002Fdocs\u002Fcohere-embed",{"title":550,"url":551},"Qwen: Qwen3-Embedding-8B model card","https:\u002F\u002Fhuggingface.co\u002FQwen\u002FQwen3-Embedding-8B",{"title":553,"url":554},"Google Developers Blog: Introducing EmbeddingGemma (Sep 2025)","https:\u002F\u002Fdevelopers.googleblog.com\u002Fen\u002Fintroducing-embeddinggemma\u002F","\u002Fimages\u002Fblog\u002Fembedding-model-selection-2026\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fembedding-model-selection-2026\u002Fog.jpg",[46,47,48],"Choosing an embedding model in 2026: leaderboards, costs and a bake-off on your own data","How to pick an embedding model for RAG in 2026: what MTEB and RTEB tell you, hosted vs open weights, prices, dimensions, and a one-week bake-off.","Three columns of stacked blocks, the middle tallest, each measured by a short bar and a wide bracket.",{"slug":562,"published":489,"minutes":6,"category":7,"tags":563,"keywords":567,"about":579,"sources":589,"cover":614,"og":615,"expertise":44,"locales":616,"lang":46,"title":617,"description":618,"coverAlt":619},"contextual-retrieval-late-chunking",[12,564,492,565,566],"Chunking","Contextual retrieval","Late chunking",[568,569,570,571,572,573,574,575,576,577,578],"contextual retrieval","anthropic contextual retrieval","late chunking","contextual chunk embeddings","contextual embeddings rag","contextual bm25","chunk context rag","voyage-context-3","voyage-context-4","late chunking vs contextual retrieval","rag chunking context loss",[580,583,586],{"name":581,"url":582},"Retrieval-augmented generation","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRetrieval-augmented_generation",{"name":584,"url":585},"Okapi BM25","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FOkapi_BM25",{"name":587,"url":588},"Sentence embedding","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSentence_embedding",[590,593,596,599,602,605,608,611],{"title":591,"url":592},"Anthropic: Introducing Contextual Retrieval (Sep 2024)","https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fcontextual-retrieval",{"title":594,"url":595},"Günther et al.: Late Chunking, Contextual Chunk Embeddings Using Long-Context Embedding Models (2024, rev. 2025)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2409.04701",{"title":597,"url":598},"Jina AI: Late Chunking in Long-Context Embedding Models (Aug 2024)","https:\u002F\u002Fjina.ai\u002Fnews\u002Flate-chunking-in-long-context-embedding-models\u002F",{"title":600,"url":601},"Voyage AI: Introducing voyage-context-3 (Jul 2025)","https:\u002F\u002Fblog.voyageai.com\u002F2025\u002F07\u002F23\u002Fvoyage-context-3\u002F",{"title":603,"url":604},"Voyage AI: voyage-context-4 (Jun 2026)","https:\u002F\u002Fblog.voyageai.com\u002F2026\u002F06\u002F29\u002Fvoyage-context-4\u002F",{"title":606,"url":607},"Voyage AI: Contextualized chunk embeddings documentation","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fcontextualized-chunk-embeddings",{"title":609,"url":610},"Anthropic: Claude API pricing","https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fabout-claude\u002Fpricing",{"title":612,"url":613},"Qu, Tu and Bao: Is Semantic Chunking Worth the Computational Cost? (2024)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2410.13070","\u002Fimages\u002Fblog\u002Fcontextual-retrieval-late-chunking\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fcontextual-retrieval-late-chunking\u002Fog.jpg",[46,47,48],"Contextual retrieval and late chunking: giving RAG chunks back their context","Chunks lose their document. How contextual retrieval, late chunking and contextualized embedding models fix that, what each costs, and when to skip it.","Four loose square pieces gathered by a wide bracket below, each joined upward to a large sheet.",{"slug":621,"published":489,"minutes":490,"category":7,"tags":622,"keywords":626,"about":639,"sources":647,"cover":671,"og":672,"expertise":44,"locales":673,"lang":46,"title":674,"description":675,"coverAlt":676},"rag-access-control-permissions",[12,623,624,625,9],"Access control","Security","Multi-tenancy",[627,628,629,630,631,632,633,634,635,636,637,638],"rag access control","permission aware rag","document level security rag","rag multi tenancy","vector database access control","pgvector row level security","security trimming azure ai search","openfga rag authorization","qdrant multitenancy","pinecone namespaces multitenancy","owasp llm08 vector and embedding weaknesses","rag data leakage",[640,643,646],{"name":641,"url":642},"Access-control list","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAccess-control_list",{"name":644,"url":645},"Multitenancy","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMultitenancy",{"name":581,"url":582},[648,651,654,656,659,662,665,668],{"title":649,"url":650},"OWASP GenAI Security Project: LLM08:2025 Vector and Embedding Weaknesses","https:\u002F\u002Fgenai.owasp.org\u002Fllmrisk\u002Fllm082025-vector-and-embedding-weaknesses\u002F",{"title":652,"url":653},"PostgreSQL documentation: Row Security Policies","https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fddl-rowsecurity.html",{"title":655,"url":23},"pgvector README: filtering and iterative index scans",{"title":657,"url":658},"Qdrant: Multitenancy and partitions guide","https:\u002F\u002Fqdrant.tech\u002Fdocumentation\u002Fguides\u002Fmultiple-partitions\u002F",{"title":660,"url":661},"Pinecone: Implement multitenancy using namespaces","https:\u002F\u002Fdocs.pinecone.io\u002Fguides\u002Findex-data\u002Fimplement-multitenancy",{"title":663,"url":664},"Microsoft Learn: Document-level access control in Azure AI Search","https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsearch-document-level-access-overview",{"title":666,"url":667},"OpenFGA: RAG authorization use case","https:\u002F\u002Fopenfga.dev\u002Fdocs\u002Fuse-cases\u002Frag-authorization",{"title":669,"url":670},"Morris et al.: Text Embeddings Reveal (Almost) As Much As Text (EMNLP 2023)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2310.06816","\u002Fimages\u002Fblog\u002Frag-access-control-permissions\u002Fcover.webp","\u002Fimages\u002Fblog\u002Frag-access-control-permissions\u002Fog.jpg",[46,47,48],"Access control for RAG: permission-aware retrieval without leaking documents","How RAG assistants leak documents and how to stop it: ACLs on every chunk, pre-filtering, row-level security in pgvector, permission sync and leak tests.","Seven cards in a row, six with a lock badge, one bare card sending an arrow outward.",{"slug":678,"published":489,"minutes":6,"category":7,"tags":679,"keywords":684,"about":696,"sources":704,"cover":731,"og":732,"expertise":733,"locales":734,"lang":46,"title":735,"description":736,"coverAlt":737},"rag-product-catalog-pim-data",[12,680,681,682,683],"PIM","Product data","B2B e-commerce","Metadata filtering",[685,686,687,688,689,690,691,692,693,694,695],"rag product catalog","rag pim data","llm product data","product catalog chatbot","akeneo rag","pimcore ai search","rag structured data","metadata filtering rag","product attributes embeddings","b2b product assistant","etim classification ai",[697,700,701],{"name":698,"url":699},"Product information management","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FProduct_information_management",{"name":581,"url":582},{"name":702,"url":703},"ETIM (standard)","https:\u002F\u002Fwww.etim-international.com\u002Fclassification\u002F",[705,708,711,714,716,719,722,725,728],{"title":706,"url":707},"Akeneo API: Products, product values, metric values and product models","https:\u002F\u002Fapi.akeneo.com\u002Fconcepts\u002Fproducts.html",{"title":709,"url":710},"Akeneo Help Center: What about products with variants?","https:\u002F\u002Fhelp.akeneo.com\u002Fserenity-take-the-power-over-your-products\u002Fserenity-what-about-products-with-variants",{"title":712,"url":713},"Pimcore documentation: Classification Store","https:\u002F\u002Fdocs.pimcore.com\u002Fplatform\u002FPimcore\u002FObjects\u002FObject_Classes\u002FData_Types\u002FClassification_Store\u002F",{"title":715,"url":703},"ETIM International: Classification",{"title":717,"url":718},"ETIM International: ETIM releases and the IXF format","https:\u002F\u002Fetim-international.com\u002F?p=754",{"title":720,"url":721},"Reddy et al.: Shopping Queries Dataset, a large-scale ESCI benchmark for improving product search (2022)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2206.06588",{"title":723,"url":724},"Amazon Science: esci-data repository","https:\u002F\u002Fgithub.com\u002Famazon-science\u002Fesci-data",{"title":726,"url":727},"Qdrant documentation: Filtering","https:\u002F\u002Fqdrant.tech\u002Fdocumentation\u002Fconcepts\u002Ffiltering\u002F",{"title":729,"url":730},"Sui et al.: Table Meets LLM, can large language models understand structured table data? (WSDM 2024)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2305.13062","\u002Fimages\u002Fblog\u002Frag-product-catalog-pim-data\u002Fcover.webp","\u002Fimages\u002Fblog\u002Frag-product-catalog-pim-data\u002Fog.jpg","b2b-ecommerce-developer",[46,47,48],"RAG over product catalogues: turning PIM data into answers that hold","Product data is structured, so chunking it like PDFs fails. How to serialize PIM attributes, route spec questions to filters and keep answers exact.","A frame of nine squares with tiny symbols, funnelling down to one card.",1792261155827]