Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions docs/db_control/serverless-indexes.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,133 @@ pc.create_index(
)
```

## Read Capacity Configuration

You can configure the read capacity mode for your serverless index. By default, indexes are created with `OnDemand` mode. You can also specify `Dedicated` mode with dedicated read nodes.

### Dedicated Read Capacity

Dedicated mode allocates dedicated read nodes for your workload. You must specify `node_type`, `scaling`, and scaling configuration.

```python
from pinecone import (
Pinecone,
ServerlessSpec,
CloudProvider,
GcpRegion,
Metric
)

pc = Pinecone(api_key='<<PINECONE_API_KEY>>')

pc.create_index(
name='my-index',
dimension=1536,
metric=Metric.COSINE,
spec=ServerlessSpec(
cloud=CloudProvider.GCP,
region=GcpRegion.US_CENTRAL1,
read_capacity={
"mode": "Dedicated",
"dedicated": {
"node_type": "t1",
"scaling": "Manual",
"manual": {
"shards": 2,
"replicas": 2
}
}
}
)
)
```

### Configuring Read Capacity

You can change the read capacity configuration of an existing serverless index using `configure_index`. This allows you to:

- Switch between OnDemand and Dedicated modes
- Adjust the number of shards and replicas for Dedicated mode with manual scaling

```python
from pinecone import Pinecone

pc = Pinecone(api_key='<<PINECONE_API_KEY>>')

# Switch to OnDemand read capacity
pc.configure_index(
name='my-index',
read_capacity={"mode": "OnDemand"}
)

# Switch to Dedicated read capacity with manual scaling
pc.configure_index(
name='my-index',
read_capacity={
"mode": "Dedicated",
"dedicated": {
"node_type": "t1",
"scaling": "Manual",
"manual": {
"shards": 3,
"replicas": 2
}
}
}
)

# Scale up by increasing shards and replicas
pc.configure_index(
name='my-index',
read_capacity={
"mode": "Dedicated",
"dedicated": {
"node_type": "t1",
"scaling": "Manual",
"manual": {
"shards": 4,
"replicas": 3
}
}
}
)
```

When you change read capacity configuration, the index will transition to the new configuration. You can use `describe_index` to check the status of the transition.

## Metadata Schema Configuration

You can configure which metadata fields are filterable by specifying a metadata schema. By default, all metadata fields are indexed. However, large amounts of metadata can cause slower index building as well as slower query execution, particularly when data is not cached in a query executor's memory and local SSD and must be fetched from object storage.

To prevent performance issues due to excessive metadata, you can limit metadata indexing to the fields that you plan to use for query filtering. When you specify a metadata schema, only fields marked as `filterable: True` are indexed and can be used in filters.

```python
from pinecone import (
Pinecone,
ServerlessSpec,
CloudProvider,
AwsRegion,
Metric
)

pc = Pinecone(api_key='<<PINECONE_API_KEY>>')

pc.create_index(
name='my-index',
dimension=1536,
metric=Metric.COSINE,
spec=ServerlessSpec(
cloud=CloudProvider.AWS,
region=AwsRegion.US_WEST_2,
schema={
"genre": {"filterable": True},
"year": {"filterable": True},
"description": {"filterable": True}
}
)
)
```

## Configuring, listing, describing, and deleting

See [shared index actions](shared-index-actions.md) to learn about how to manage the lifecycle of your index after it is created.
23 changes: 23 additions & 0 deletions pinecone/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,29 @@
"pinecone.db_control.types",
"CreateIndexForModelEmbedTypedDict",
),
# Read capacity TypedDict classes
"ScalingConfigManualDict": (
"pinecone.db_control.models.serverless_spec",
"ScalingConfigManualDict",
),
"ReadCapacityDedicatedConfigDict": (
"pinecone.db_control.models.serverless_spec",
"ReadCapacityDedicatedConfigDict",
),
"ReadCapacityOnDemandDict": (
"pinecone.db_control.models.serverless_spec",
"ReadCapacityOnDemandDict",
),
"ReadCapacityDedicatedDict": (
"pinecone.db_control.models.serverless_spec",
"ReadCapacityDedicatedDict",
),
"ReadCapacityDict": ("pinecone.db_control.models.serverless_spec", "ReadCapacityDict"),
# Metadata schema TypedDict class
"MetadataSchemaFieldConfig": (
"pinecone.db_control.models.serverless_spec",
"MetadataSchemaFieldConfig",
),
}

_config_lazy_imports = {
Expand Down
28 changes: 28 additions & 0 deletions pinecone/db_control/models/backup_model.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
import json
from typing import Optional, TYPE_CHECKING
from pinecone.core.openapi.db_control.model.backup_model import BackupModel as OpenAPIBackupModel
from pinecone.utils.repr_overrides import custom_serializer

if TYPE_CHECKING:
from pinecone.core.openapi.db_control.model.backup_model_schema import BackupModelSchema


class BackupModel:
"""Represents a Pinecone backup configuration and status.

The BackupModel describes the configuration and status of a Pinecone backup,
including metadata about the source index, backup location, and schema
configuration.
"""

def __init__(self, backup: OpenAPIBackupModel):
self._backup = backup

@property
def schema(self) -> Optional["BackupModelSchema"]:
"""Schema for the behavior of Pinecone's internal metadata index.

This property defines which metadata fields are indexed and filterable
in the backup. By default, all metadata is indexed. When ``schema`` is
present, only fields which are present in the ``fields`` object with
``filterable: true`` are indexed.

The schema is a map of metadata field names to their configuration,
where each field configuration specifies whether the field is filterable.

:type: BackupModelSchema, optional
:returns: The metadata schema configuration, or None if not set.
"""
return getattr(self._backup, "schema", None)

def __getattr__(self, attr):
return getattr(self._backup, attr)

Expand Down
96 changes: 94 additions & 2 deletions pinecone/db_control/models/serverless_spec.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,117 @@
from dataclasses import dataclass
from typing import Union
from typing import Union, Optional, Dict, Any, TypedDict, TYPE_CHECKING, Literal
from enum import Enum

try:
from typing_extensions import NotRequired
except ImportError:
try:
from typing import NotRequired # type: ignore
except ImportError:
# Fallback for older Python versions - NotRequired not available
NotRequired = None # type: ignore

from ..enums import CloudProvider, AwsRegion, GcpRegion, AzureRegion

if TYPE_CHECKING:
from pinecone.core.openapi.db_control.model.read_capacity import ReadCapacity
from pinecone.core.openapi.db_control.model.read_capacity_on_demand_spec import (
ReadCapacityOnDemandSpec,
)
from pinecone.core.openapi.db_control.model.read_capacity_dedicated_spec import (
ReadCapacityDedicatedSpec,
)


class ScalingConfigManualDict(TypedDict, total=False):
"""TypedDict for manual scaling configuration."""

shards: int
replicas: int


if NotRequired is not None:
# Python 3.11+ or typing_extensions available - use NotRequired for better type hints
class ReadCapacityDedicatedConfigDict(TypedDict):
"""TypedDict for dedicated read capacity configuration.

Required fields: node_type, scaling
Optional fields: manual
"""

node_type: str # Required: "t1" or "b1"
scaling: str # Required: "Manual" or other scaling types
manual: NotRequired[ScalingConfigManualDict] # Optional
else:
# Fallback for older Python versions - all fields optional
class ReadCapacityDedicatedConfigDict(TypedDict, total=False): # type: ignore[no-redef]
"""TypedDict for dedicated read capacity configuration.

Note: In older Python versions without NotRequired support, all fields
are marked as optional. However, node_type and scaling are required
when using Dedicated mode. Users must provide these fields.
"""

node_type: str # Required: "t1" or "b1"
scaling: str # Required: "Manual" or other scaling types
manual: ScalingConfigManualDict # Optional


class ReadCapacityOnDemandDict(TypedDict):
"""TypedDict for OnDemand read capacity mode."""

mode: Literal["OnDemand"]


class ReadCapacityDedicatedDict(TypedDict):
"""TypedDict for Dedicated read capacity mode."""

mode: Literal["Dedicated"]
dedicated: ReadCapacityDedicatedConfigDict


ReadCapacityDict = Union[ReadCapacityOnDemandDict, ReadCapacityDedicatedDict]

if TYPE_CHECKING:
ReadCapacityType = Union[
ReadCapacityDict, "ReadCapacity", "ReadCapacityOnDemandSpec", "ReadCapacityDedicatedSpec"
]
else:
ReadCapacityType = Union[ReadCapacityDict, Any]


class MetadataSchemaFieldConfig(TypedDict):
"""TypedDict for metadata schema field configuration."""

filterable: bool


@dataclass(frozen=True)
class ServerlessSpec:
cloud: str
region: str
read_capacity: Optional[ReadCapacityType] = None
schema: Optional[Dict[str, MetadataSchemaFieldConfig]] = None

def __init__(
self,
cloud: Union[CloudProvider, str],
region: Union[AwsRegion, GcpRegion, AzureRegion, str],
read_capacity: Optional[ReadCapacityType] = None,
schema: Optional[Dict[str, MetadataSchemaFieldConfig]] = None,
):
# Convert Enums to their string values if necessary
object.__setattr__(self, "cloud", cloud.value if isinstance(cloud, Enum) else str(cloud))
object.__setattr__(
self, "region", region.value if isinstance(region, Enum) else str(region)
)
object.__setattr__(self, "read_capacity", read_capacity)
object.__setattr__(self, "schema", schema)

def asdict(self):
return {"serverless": {"cloud": self.cloud, "region": self.region}}
result = {"serverless": {"cloud": self.cloud, "region": self.region}}
if self.read_capacity is not None:
result["serverless"]["read_capacity"] = self.read_capacity
if self.schema is not None:
result["serverless"]["schema"] = {"fields": self.schema}
return result
Loading