Getting Started
This guide walks you through creating your first graph database, performing basic operations, and exploring both embedded and service modes. Examples are in Python.
Using another language? See the Node.js API reference or C++ API reference for equivalent examples in those languages.
Prerequisites
Before you begin, make sure you have NeuG installed. If you haven’t installed it yet, please follow the installation guide.
Database Storage Modes
Persistent Database
- Use case: Production applications, data analysis, long-term storage
- Durability: Data survives application restarts
# Persistent mode examples
# Make sure that the database directory exists and is writable by the user.
db_persistent = neug.Database("/path/to/database")In-Memory Database
- Use case: Temporary computations, testing, prototyping
- Durability: Data is lost when the process ends
# Memory mode examples
db_memory = neug.Database("")Note: Currently, NeuG’s in-memory mode creates a temporary database directory that is automatically cleaned up when the process exits.
Connection Modes
NeuG provides two modes to access your database:
Embedded Mode
Direct in-process access - easiest for single-user scenarios:
import neug
# Create database and connect directly
db = neug.Database("/path/to/database") # or "" for in-memory
conn = db.connect()
print("Connect to NeuG in embedded mode")
conn.close()
db.close()Service Mode
Network-based access - ideal for multi-user applications:
Start the service:
import neug
# Start NeuG as a service
db = neug.Database("/path/to/database")
service = db.serve(host="localhost", port=10000, blocking=False, thread_num=0)thread_num controls the number of service threads.
The default 0 auto-selects from the database max_thread_num. With the
default database thread setting, max_thread_num is resolved from hardware
concurrency and falls back to 1 if the runtime cannot detect it.
Connect from client:
from neug import Session
# Connect to the service
session = Session("http://localhost:10000/")
session.close()Basic Operations
The following operations work the same way regardless of which database mode (in-memory or persistent) and connection mode (embedded or service) you choose. Let’s assume that we are using a persistent database in embedded mode for this example.
import neug
# Create database and establish connection
db = neug.Database("/path/to/database")
conn = db.connect()Creating Nodes and Edges
Before inserting data, you need to define your graph schema with node and edge types:
# Create node tables
conn.execute("""
CREATE NODE TABLE Person(
id INT64 PRIMARY KEY,
name STRING,
age INT64,
email STRING
)
""")
conn.execute("""
CREATE NODE TABLE Company(
id INT64 PRIMARY KEY,
name STRING,
industry STRING,
founded_year INT64
)
""")
# Create edge tables
conn.execute("""
CREATE REL TABLE WORKS_FOR(
FROM Person TO Company,
position STRING,
start_date DATE,
salary DOUBLE
)
""")
conn.execute("""
CREATE REL TABLE KNOWS(
FROM Person TO Person,
since_year INT64,
relationship_type STRING
)
""")
print("Graph schema created successfully!")Inserting Data
Now let’s add some data to our graph:
# Insert nodes
conn.execute("""
CREATE (p:Person {id: 1, name: 'Alice Johnson', age: 30, email: '[email protected]'})
""")
conn.execute("""
CREATE (p:Person {id: 2, name: 'Bob Smith', age: 35, email: '[email protected]'})
""")
conn.execute("""
CREATE (c:Company {id: 1, name: 'TechCorp', industry: 'Technology', founded_year: 2010})
""")
# Insert relationships
conn.execute("""
MATCH (p:Person), (c:Company) WHERE p.id = 1 AND c.id = 1
CREATE (p)-[:WORKS_FOR {position: 'Software Engineer', start_date: date('2020-01-15'), salary: 75000.0}]->(c)
""")
conn.execute("""
MATCH (p1:Person {id: 2}), (p2:Person {id: 1})
CREATE (p1)-[:KNOWS {since_year: 2018, relationship_type: 'colleague'}]->(p2)
""")
print("Data inserted successfully!")Querying Data
Let’s explore your graph with some queries:
# Simple node query
result = conn.execute("MATCH (p:Person) RETURN p.name, p.age")
for record in result:
print(record)
# ['Alice Johnson', 30]
# ['Bob Smith', 35]
# Relationship query
result = conn.execute("""
MATCH (p:Person)-[w:WORKS_FOR]->(c:Company)
RETURN p.name, w.position, c.name
""")
for record in result:
print(f"{record[0]} works as {record[1]} at {record[2]}")
# Alice Johnson works as Software Engineer at TechCorp
# Complex pattern query
result = conn.execute("""
MATCH (p1:Person)-[:KNOWS]->(p2:Person)-[:WORKS_FOR]->(c:Company)
RETURN p1.name as person1, p2.name as person2, c.name as company
""")
for record in result:
print(f"{record[0]} knows {record[1]} who works at {record[2]}")
# Bob Smith knows Alice Johnson who works at TechCorpConverting Results to Apache Arrow
NeuG supports converting query results directly to Apache Arrow tables via the to_arrow() method. This enables zero-copy interoperability with the PyData ecosystem — pandas, Polars, DuckDB, and any other library that understands Arrow.
import neug
db = neug.Database("/path/to/database")
conn = db.connect()
# Run a query and convert to Arrow table
result = conn.execute("""
MATCH (p:Person)-[w:WORKS_FOR]->(c:Company)
RETURN p.name AS name, p.age AS age, w.salary AS salary, c.name AS company
""")
arrow_table = result.to_arrow()
print(arrow_table)
# pyarrow.Table
# name: string
# age: int64
# salary: double
# company: string
# Convert to a pandas DataFrame
df = arrow_table.to_pandas()
print(df)
# name age salary company
# 0 Alice Johnson 30 75000.0 TechCorpNote:
to_arrow()requires PyArrow to be installed (pip install pyarrow). The returnedpyarrow.Tablepreserves column names from theRETURNclause of your Cypher query.
Close the connection and database
conn.close()
db.close()Using builtin dataset
NeuG provides several builtin datasets that you can use to quickly get started with graph analysis, learning, or testing. These datasets are ready-to-use and require no setup.
Available Datasets
You can list all available builtin datasets:
from neug.datasets import get_available_datasets
# List all available datasets
datasets = get_available_datasets()
for dataset in datasets:
print(f"{dataset.name}: {dataset.description}")Loading Builtin Datasets
import neug
# Open/create a database
db = neug.Database("/path/to/database")
# Load a builtin dataset into it
db.load_builtin_dataset(dataset_name="modern_graph")Note: Loading a builtin dataset into an existing database will fail if there are schema conflicts (e.g., existing node/edge types with the same names).
Next Steps
Congratulations! You’ve learned the basics of NeuG. Here’s what you can explore next:
- Data Import/Export: Learn how to import large datasets
- Advanced Cypher Queries: Master complex graph patterns
- Tutorials: Try these interesting tutorials of NeuG