Source code for pinecone.models.vectors.vector

"""The vector record you upsert, and the scored match a query returns."""

from __future__ import annotations

from typing import Any

from msgspec import Struct

from pinecone.errors.exceptions import PineconeValueError
from pinecone.models._mixin import DictLikeStruct
from pinecone.models.vectors.sparse import SparseValues


[docs] class Vector(DictLikeStruct, Struct, rename="camel", gc=False): """One record in a vector-based index: an ID, its coordinates, and its metadata. A vector carries its coordinates in either or both of two representations, and which ones you populate is what makes a vector dense, sparse, or hybrid: * **Dense** — ``values``, a list of floats whose length equals the ``dimension`` of the index field it is written to, ranked by that field's ``metric``. This is the usual output of an embedding model, and the representation that finds records by meaning. Build a dense vector when you have an embedding. * **Sparse** — ``sparse_values``, which names only the non-zero dimensions as parallel ``indices`` and ``values`` lists and has no fixed ``dimension``. This is how keyword-based scoring such as BM25 is expressed, and it finds records by exact term. Build a sparse vector when the terms themselves matter. * **Hybrid** — both populated on the same vector, so one record is reachable by meaning and by term. The index has to declare a dense field and a sparse field for this to be accepted. At least one of the two must be populated. A sparse-only vector leaves ``values`` empty, and the empty dense list is still sent. Attributes: id (str): Unique identifier for the vector; the client rejects an ID that is not ASCII, is empty, is over 512 characters, or contains NUL. Use an ID you can recompute from your own data, e.g. ``"article-101"``. values (list[float]): Dense vector values. Empty for a sparse-only vector. sparse_values (SparseValues | None): Sparse component, or ``None`` for a dense-only vector. metadata (dict[str, Any] | None): Your own key-value pairs to filter on later, or ``None`` if none are attached. Each value must be a string, a number, a boolean, or a list of strings — a nested object, or a list with a non-string element, is rejected. A key whose value is ``None`` is dropped rather than rejected. Keys may not begin with ``$``, which is reserved for filter operators; every other key is accepted, including empty and non-ASCII keys. Raises: PineconeValueError: If neither ``values`` nor ``sparse_values`` is populated — a vector with no coordinates cannot be scored against anything. Examples: A dense vector. Pass the embedding your model produced; its length has to match the dimension of the field you upsert into, so the three floats here stand in for a full-length embedding. >>> from pinecone import Vector >>> dense = Vector(id="article-101", values=[0.12, 0.34, 0.56]) >>> dense.sparse_values is None True A sparse vector, where each index is a term slot that scored non-zero. ``values`` comes back empty because nothing dense was supplied. >>> from pinecone import SparseValues >>> sparse = Vector( ... id="article-102", ... sparse_values=SparseValues(indices=[10, 42, 913], values=[0.4, 0.9, 0.2]), ... ) >>> sparse.values [] A hybrid vector populates both, and can carry metadata to filter on. >>> hybrid = Vector( ... id="article-103", ... values=[0.12, 0.34, 0.56], ... sparse_values=SparseValues(indices=[10, 42], values=[0.4, 0.9]), ... metadata={"lang": "en", "published": True}, ... ) >>> len(hybrid.values), len(hybrid.sparse_values.indices) (3, 2) .. seealso:: :class:`ScoredVector` — what a query returns for each match, which adds ``score``. :class:`~pinecone.models.documents.document.DocumentRecord` — the record type for schema-based indexes, which store JSON documents rather than raw vectors. """ id: str values: list[float] = [] sparse_values: SparseValues | None = None metadata: dict[str, Any] | None = None def __post_init__(self) -> None: """Require at least one of ``values`` or ``sparse_values`` to be populated.""" if not self.values and self.sparse_values is None: raise PineconeValueError("Vector must have either values or sparse_values")
[docs] @staticmethod def from_dict(vector_dict: dict[str, Any]) -> Vector: """Build a :class:`Vector` from a plain dict. Accepts the snake_case keys ``id``, ``values``, ``sparse_values`` and ``metadata``. Use it when your vectors arrive as dicts — from your own JSON, a dataframe row, or a previous ``to_dict()`` — and you want the same construction-time check that ``Vector(...)`` applies. Args: vector_dict (dict[str, Any]): The dict to convert. ``id`` is required; the rest are optional and default the same way the constructor does. Returns: :class:`Vector` with ``sparse_values`` decoded into a :class:`SparseValues`. Raises: KeyError: If ``id`` is absent. PineconeValueError: If neither ``values`` nor ``sparse_values`` is populated. Examples: >>> from pinecone import Vector >>> Vector.from_dict({"id": "article-101", "values": [0.12, 0.34, 0.56]}).id 'article-101' """ sparse: SparseValues | None = None if vector_dict.get("sparse_values") is not None: sparse = SparseValues.from_dict(vector_dict["sparse_values"]) return Vector( id=vector_dict["id"], values=vector_dict.get("values", []), sparse_values=sparse, metadata=vector_dict.get("metadata"), )
def __repr__(self) -> str: if len(self.values) > 5: preview = ", ".join(repr(v) for v in self.values[:3]) values_str = f"[{preview}, ...{len(self.values) - 3} more]" else: values_str = repr(self.values) parts = [ f"id={self.id!r}", f"values={values_str}", f"sparse_values={self.sparse_values!r}", ] if self.metadata is not None: parts.append(f"metadata={self.metadata!r}") return f"Vector({', '.join(parts)})"
[docs] class ScoredVector(DictLikeStruct, Struct, rename="camel", kw_only=True, gc=False): """One match from a query: the vector that was found, plus how close it was. Every element of :attr:`QueryResponse.matches <pinecone.models.vectors.responses.QueryResponse.matches>` is one of these, so ``id`` and ``score`` are always populated. ``values`` and ``metadata`` are not: a query omits both unless you ask for them, so an empty ``values`` or a ``None`` ``metadata`` usually means the request did not set the corresponding flag rather than that the stored vector lacks them. Attributes: id (str): Identifier of the matched vector, the same ID it was upserted under. score (float): How close the match is under the queried field's ``metric``. Higher is closer for ``cosine`` and ``dotproduct``; lower is closer for ``euclidean``. Compare scores only within one response — the scale depends on the metric and on your data, so no fixed threshold means "good" across indexes. values (list[float]): Dense values of the matched vector, or ``[]`` when the query did not pass ``include_values=True``. sparse_values (SparseValues | None): Sparse component of the matched vector, or ``None`` for a dense-only vector or when values were not requested. metadata (dict[str, Any] | None): The metadata stored with the vector, or ``None`` when the query did not pass ``include_metadata=True`` or nothing was stored. Values follow the same grammar as :attr:`Vector.metadata`. Examples: A query returns these in ``matches``, ordered most similar first, so reading a result is the same two attributes every time. .. code-block:: python response = idx.query(top_k=5, vector=[0.012, -0.087, 0.153]) for match in response.matches: print(match.id, match.score) Ask for metadata if you intend to read it — without the flag ``match.metadata`` is ``None`` even for vectors that have metadata stored. .. code-block:: python response = idx.query( top_k=5, vector=[0.012, -0.087, 0.153], namespace="articles-en", include_metadata=True, ) for match in response.matches: print(match.id, match.metadata["lang"]) """ id: str score: float values: list[float] = [] sparse_values: SparseValues | None = None metadata: dict[str, Any] | None = None def __repr__(self) -> str: if len(self.values) > 5: preview = ", ".join(repr(v) for v in self.values[:3]) values_str = f"[{preview}, ...{len(self.values) - 3} more]" else: values_str = repr(self.values) parts = [ f"id={self.id!r}", f"score={self.score!r}", f"values={values_str}", ] if self.sparse_values is not None: parts.append(f"sparse_values={self.sparse_values!r}") if self.metadata is not None: parts.append(f"metadata={self.metadata!r}") return f"ScoredVector({', '.join(parts)})"