Schema API¶
The Schema provides type management, index creation, and property definitions for documents, vertices, and edges.
Overview¶
The Schema class enables:
- Type Management: Create document, vertex, and edge types
- Property Definitions: Define typed properties with constraints
- Index Creation: Create indexes for query optimization
- Type Hierarchies: Extend existing types
- Schema Inspection: Query existing schema definitions
DSL-first recommendation
For application code, prefer ArcadeDB SQL DDL via db.command("sql", ...).
This page documents the Schema wrapper API for reference and advanced typed schema workflows.
Getting Schema¶
import arcadedb_embedded as arcadedb
# Use context manager to ensure clean close
with arcadedb.create_database("./mydb") as db:
# Create types (Schema operations are auto-transactional)
# Vertex type
user_type = db.schema.create_vertex_type("User")
# Edge type
follows_type = db.schema.create_edge_type("Follows")
# Document type
log_type = db.schema.create_document_type("LogEntry")
Auto-Transactional
Schema operations (create type, create property, create index) are auto-transactional.
Do not wrap them in with db.transaction(): blocks.
Type Creation Methods¶
create_vertex_type¶
Create a new vertex type. Returns the underlying Java VertexType object.
Parameters:
name(str): Name of the vertex typebuckets(Optional[int]): Number of buckets (engine default 3 when omitted)
Returns:
VertexType: Created vertex type
Example:
# Schema operations are auto-transactional
# Basic vertex type
user_type = schema.create_vertex_type("User")
# With custom buckets
product_type = schema.create_vertex_type("Product", buckets=10)
create_edge_type¶
Create a new edge type. Returns the underlying Java EdgeType object.
Parameters:
name(str): Name of the edge typebuckets(Optional[int]): Number of buckets (engine default 3 when omitted)
Returns:
EdgeType: Created edge type
Example:
# Schema operations are auto-transactional
# Basic edge type
follows_type = schema.create_edge_type("Follows")
# With custom buckets
purchased_type = schema.create_edge_type("Purchased", buckets=5)
create_document_type¶
Create a new document type. Returns the underlying Java DocumentType object.
Parameters:
name(str): Name of the document typebuckets(Optional[int]): Number of buckets (engine default 3 when omitted)
Returns:
DocumentType: Created document type
Example:
# Schema operations are auto-transactional
# Basic document type
log_type = schema.create_document_type("LogEntry")
# With custom buckets
event_type = schema.create_document_type("Event", buckets=8)
Property Definition¶
create_property¶
schema.create_property(
type_name: str,
property_name: str,
property_type: Union[str, PropertyType],
of_type: Optional[str] = None
) -> Any
Create a property on a type. Returns the underlying Java Property object.
Parameters:
type_name(str): Name of the typeproperty_name(str): Name of the propertyproperty_type(str orPropertyType): ArcadeDB type (see types below)of_type(Optional[str]): Element type forLIST/MAPcollections
Returns:
- Java
Propertyobject
Property Types:
The PropertyType enum (importable as from arcadedb_embedded import PropertyType)
defines the supported values:
- Primitives:
STRING,INTEGER,LONG,SHORT,BYTE,BOOLEAN,FLOAT,DOUBLE,DECIMAL,DATE,DATETIME - Binary:
BINARY - Collections:
LIST,MAP,EMBEDDED - Links:
LINK - Vectors:
ARRAY_OF_FLOATS
Either the enum member or its string name may be passed.
Example:
# Schema operations are auto-transactional
schema.create_vertex_type("User")
# String property
schema.create_property("User", "name", "STRING")
# Integer property (enum form)
from arcadedb_embedded import PropertyType
schema.create_property("User", "age", PropertyType.INTEGER)
# Date property
schema.create_property("User", "birthDate", "DATE")
# List property
schema.create_property("User", "tags", "LIST", of_type="STRING")
# Embedded property
schema.create_property("User", "profile", "EMBEDDED")
get_or_create_property¶
schema.get_or_create_property(
type_name: str,
property_name: str,
property_type: Union[str, PropertyType],
of_type: Optional[str] = None
) -> Any
Get an existing property or create it if it doesn't exist. Same parameters as
create_property. Returns the underlying Java Property object.
drop_property¶
Drop a property from a type.
Property constraints
Constraints such as mandatory, not-null, default, and min/max are configured on the
returned Java Property object (for example prop.setMandatory(True)) or via SQL
DDL. The Python Schema wrapper itself only exposes property creation/removal.
Index Creation¶
create_index¶
schema.create_index(
type_name: str,
property_names: List[str],
unique: bool = False,
index_type: Union[str, IndexType] = "LSM_TREE"
) -> Index
Create an index on a type.
Parameters:
type_name(str): Name of the typeproperty_names(List[str]): List of property names to indexunique(bool): Whether the index should enforce uniqueness (default:False)index_type(str or IndexType): Type of index ("LSM_TREE","HASH","FULL_TEXT","LSM_VECTOR","GEOSPATIAL")
Returns:
Index: Created index object
Raises:
ArcadeDBError: If type doesn't exist or index creation fails
Example:
# Schema operations are auto-transactional
# Unique index on username
schema.create_index("User", ["username"], unique=True)
# Exact-match lookup index
schema.create_index("Order", ["customerId"], index_type="HASH")
# Composite index
schema.create_index("Event", ["userId", "timestamp"])
# Full-text index
schema.create_index("Article", ["content"], index_type="FULL_TEXT")
Index choice rules of thumb:
- Use
HASHfor exact-match lookups when you do not need ranges or ordered scans. - Use
LSM_TREEwhen you need ranges, sorting, or a safe general-purpose default. - Use
FULL_TEXT,LSM_VECTOR, andGEOSPATIALonly for their specialized query types. HASHcan be unique or non-unique. The index structure and uniqueness constraint are separate choices.
SQL DSL equivalents:
CREATE INDEX ON User (email) UNIQUE-> uniqueLSM_TREECREATE INDEX ON User (email) NOTUNIQUE-> non-uniqueLSM_TREECREATE INDEX ON User (email) UNIQUE_HASH-> uniqueHASHCREATE INDEX ON Order (customerId) NOTUNIQUE_HASH-> non-uniqueHASHCREATE INDEX ON Article (content) FULL_TEXT->FULL_TEXTCREATE INDEX ON Doc (embedding) LSM_VECTOR ...->LSM_VECTORCREATE INDEX ON Place (location) GEOSPATIAL->GEOSPATIAL
Vector (JVector) Parameters:
Note
schema.create_index() only accepts type_name, property_names, unique, and
index_type. It does not take the JVector tuning parameters below. To configure a
vector index from Python, use db.create_vector_index()
(which exposes max_connections, beam_width, dimensions, etc.), or SQL
CREATE INDEX ... LSM_VECTOR METADATA {...}.
- max_connections: Max connections per node (default: 16; typical 8-32). Maps to
JVector
maxConnections. - beam_width: Beam width for build/search (default: 100; typical 64-200). Maps to
JVector
beamWidth. - dimensions: Vector size (must match your embeddings).
- ef_search: Query-time exact-search beam width override via SQL
vectorNeighbors(..., k, ef_search). Leave unset to use ArcadeDB's default/adaptive behavior.
Type Inspection¶
get_type¶
Get a type by name.
Parameters:
type_name(str): Name of the type
Returns:
Optional[Type]: JavaDocumentType/VertexType/EdgeTypeobject, orNoneif not found. Methods on this object are the underlying Java methods exposed by JPype (camelCase, e.g.getName(),countType(True)).
Example:
# Check if type exists
user_type = schema.get_type("User")
if user_type:
print(f"User type exists: {user_type.getName()}")
else:
print("User type not found")
exists_type¶
Check if type exists.
Parameters:
type_name(str): Name of the type
Returns:
bool: True if exists
Example:
if not schema.exists_type("User"):
schema.create_vertex_type("User") # Schema ops are auto-transactional
get_types¶
Get all types.
Returns:
List[Any]: All types in the schema as Java type objects
Example:
Type Methods¶
get_type() and get_types() return the raw Java type objects. Their methods are the
underlying Java methods exposed by JPype using camelCase names (for example getName(),
getProperties(), getIndexesByProperties(...)).
type_obj = schema.get_type("User")
# Get type info (Java methods via JPype)
name = type_obj.getName()
# Get properties (Java Property objects)
for prop in type_obj.getProperties():
print(f"{prop.getName()}: {prop.getType()}")
Prefer SQL for inspection
For schema inspection in application code, prefer SQL such as
db.query("sql", "SELECT FROM schema:types") /
db.query("sql", "SELECT FROM schema:indexes"), which returns Python-friendly
Result rows instead of raw Java objects.
Complete Example¶
import arcadedb_embedded as arcadedb
# Create database with context manager to ensure clean close
with arcadedb.create_database("./social_network") as db:
# Create schema (auto-transactional)
# User vertex type
db.schema.create_vertex_type("User")
db.schema.create_property("User", "username", "STRING")
db.schema.create_property("User", "email", "STRING")
db.schema.create_property("User", "age", "INTEGER")
db.schema.create_property("User", "tags", "LIST", of_type="STRING")
db.schema.create_property("User", "createdAt", "DATETIME")
# Post vertex type
db.schema.create_vertex_type("Post")
db.schema.create_property("Post", "title", "STRING")
db.schema.create_property("Post", "content", "STRING")
db.schema.create_property("Post", "timestamp", "DATETIME")
# Follows edge type
db.schema.create_edge_type("Follows")
db.schema.create_property("Follows", "since", "DATETIME")
# Likes edge type
db.schema.create_edge_type("Likes")
db.schema.create_property("Likes", "timestamp", "DATETIME")
# Create indexes
db.schema.create_index("User", ["username"], unique=True)
db.schema.create_index("Post", ["timestamp"])
# Verify schema (get_types() returns raw Java type objects)
print("\n📋 Schema Summary:")
for type_obj in db.schema.get_types():
print(f"\nType: {type_obj.getName()}")
for prop in type_obj.getProperties():
print(f" - {prop.getName()}: {prop.getType()}")
Schema Evolution¶
# Add property to an existing type (auto-transactional)
if db.schema.get_type("User").getProperty("phoneNumber") is None:
db.schema.create_property("User", "phoneNumber", "STRING")
print("✅ Added phoneNumber property")
# get_or_create_* helpers make evolution idempotent
db.schema.get_or_create_property("User", "phoneNumber", "STRING")
db.schema.get_or_create_index("User", ["email"], unique=True)
Best Practices¶
1. Schema Ops Are Auto-Transactional¶
# ✅ Correct
schema.create_vertex_type("User")
schema.create_edge_type("Follows")
# ❌ Unnecessary
with db.transaction():
schema.create_vertex_type("User")
2. Check Existence Before Creating¶
# ✅ Good: Check first
if not schema.exists_type("User"):
schema.create_vertex_type("User")
# ❌ Bad: Don't check
schema.create_vertex_type("User") # May error if exists
3. Create Indexes for Frequent Queries¶
# ✅ Good: Index frequently queried properties
schema.create_index("Event", ["timestamp"])
schema.create_index("Event", ["userId", "timestamp"])
4. Use Appropriate Bucket Counts¶
# ✅ Good: Scale buckets with data size
if expected_records < 100000:
buckets = 3 # Default
elif expected_records < 1000000:
buckets = 10
else:
buckets = 20
schema.create_vertex_type("BigData", buckets=buckets)
5. Set Property Constraints¶
Property constraints are not exposed by the Python Schema wrapper. Apply them via SQL
DDL, or on the Java Property object returned by create_property (camelCase methods):
# ✅ Recommended: SQL DDL for constraints (schema ops are auto-transactional)
db.schema.create_vertex_type("User")
db.command("sql", "CREATE PROPERTY User.username STRING (mandatory true, notnull true)")
db.command("sql", "CREATE PROPERTY User.age INTEGER (min 0, max 150)")
# Or configure the returned Java Property object directly
username = db.schema.create_property("User", "nickname", "STRING")
username.setMandatory(True)
username.setNotNull(True)
Common Patterns¶
1. Schema Initialization¶
def init_schema(db):
"""Initialize schema if not exists"""
if db.schema.exists_type("User"):
print("Schema already initialized")
return
# Schema operations are auto-transactional
db.schema.create_vertex_type("User")
db.schema.create_property("User", "username", "STRING")
db.schema.create_property("User", "email", "STRING")
db.schema.create_index("User", ["username"], unique=True)
print("✅ Schema initialized")
# Use it
init_schema(db)
2. Schema Export¶
def export_schema(db):
"""Export schema to dict (get_types() yields raw Java type objects)."""
schema_dict = {}
for type_obj in db.schema.get_types():
type_name = str(type_obj.getName())
schema_dict[type_name] = {"properties": {}, "indexes": []}
# Export properties (Java Property objects via JPype)
for prop in type_obj.getProperties():
schema_dict[type_name]["properties"][str(prop.getName())] = str(
prop.getType()
)
return schema_dict
# Use it
schema_export = export_schema(db)
print(json.dumps(schema_export, indent=2))
Tip
For schema export you can also query db.query("sql", "SELECT FROM schema:types")
and db.query("sql", "SELECT FROM schema:indexes"), which return Python Result
rows instead of raw Java objects.
3. Schema Migration¶
def migrate_schema_v1_to_v2(db):
"""Migrate schema from v1 to v2 (idempotent via get_or_create_*)."""
# Add new property if missing
db.schema.get_or_create_property("User", "status", "STRING")
print("✅ Ensured status property")
# Add new index if missing
db.schema.get_or_create_index("User", ["status"])
print("✅ Ensured status index")
# Use it
migrate_schema_v1_to_v2(db)
Troubleshooting¶
Type Already Exists Error¶
Property Not Found¶
# ✅ Good: Check property exists on the Java type object (camelCase JPype methods)
user_type = schema.get_type("User")
if user_type is not None and user_type.existsProperty("email"):
print(f"Email type: {user_type.getProperty('email').getType()}")
else:
print("Email property not found")
Index Creation Fails¶
See Also¶
- Database API - Database operations
- Transactions API - Transaction management
- Vector Search Guide - HNSW (JVector) indexes
- Example 03: Vector Search - Real-world schema usage
- Example 02: Social Network - Graph schema patterns