diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..b5d72502 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,73 @@ +# Examples for lance-graph + +## How to Run Examples + +Pick one of the two approaches: + +### 1) Local build (editable) with maturin + +```bash +# From the repo root; installs the Python extension in editable mode +pip install pyarrow # or: uv pip install pyarrow +maturin develop -m python/Cargo.toml + +# Run examples +python examples/basic_cypher.py +python examples/kg_traversal.py +``` + +With `uv` (persistent venv recommended): + +```bash +# Create and activate a reusable environment +uv venv .venv && . .venv/bin/activate + +# Install dependencies and build editable extension +uv pip install pyarrow +uvx --from maturin maturin develop -m python/Cargo.toml + +# Run examples using the venv's Python +python examples/basic_cypher.py +python examples/kg_traversal.py +``` + +### 2) Install the package, then run + +- From PyPI (when published): + +```bash +pip install lance-graph pyarrow +python examples/basic_cypher.py +python examples/kg_traversal.py +``` + +- From git (editable): + +```bash +pip install -e python +python examples/basic_cypher.py +python examples/kg_traversal.py +``` + +### 3) Single-shot with uv (no install, run from source) + +uv creates a fresh isolated environment per run. If you prefer a one-liner without installing the package, point `PYTHONPATH` to the source package and let uv provide `pyarrow`: + +```bash +PYTHONPATH=python/python uv run --with pyarrow python examples/basic_cypher.py +PYTHONPATH=python/python uv run --with pyarrow python examples/kg_traversal.py +``` + +## Examples + +- `basic_cypher.py`: simple node filter and projection. + +```bash +python examples/basic_cypher.py +``` + +- `kg_traversal.py`: multi-hop traversal on a small synthetic knowledge graph. + +```bash +python examples/kg_traversal.py +``` diff --git a/examples/basic_cypher.py b/examples/basic_cypher.py new file mode 100644 index 00000000..33db1c63 --- /dev/null +++ b/examples/basic_cypher.py @@ -0,0 +1,51 @@ +""" +Basic Cypher graph query using the lance-graph Python bindings. + +Requirements: +- Build/install the Python extension first (from repo root): + maturin develop -m python/Cargo.toml +- Python deps: pyarrow + +Run: + python examples/basic_cypher.py +""" + +from __future__ import annotations + +import pyarrow as pa + +from lance_graph import GraphConfigBuilder, CypherQuery + + +def make_people_batch() -> pa.RecordBatch: + return pa.record_batch( + [ + pa.array([1, 2, 3, 4, 5], type=pa.int32()), + pa.array(["Alice", "Bob", "Carol", "David", "Eve"], type=pa.string()), + pa.array([28, 34, 29, 42, 31], type=pa.int32()), + ], + names=["person_id", "name", "age"], + ) + + +def main() -> None: + config = ( + GraphConfigBuilder() + .with_node_label("Person", "person_id") + .build() + ) + + query = ( + CypherQuery("MATCH (n:Person) WHERE n.age > 30 RETURN n.name") + .with_config(config) + ) + + datasets = {"Person": make_people_batch()} + result = query.execute(datasets) + + # Convert to a simple Python dict for display + print(result.to_pydict()) + + +if __name__ == "__main__": + main() diff --git a/examples/kg_traversal.py b/examples/kg_traversal.py new file mode 100644 index 00000000..7b2215b5 --- /dev/null +++ b/examples/kg_traversal.py @@ -0,0 +1,65 @@ +""" +Simple knowledge-graph multi-hop traversal with lance-graph Python bindings. + +Requirements: +- Build/install the Python extension first (from repo root): + maturin develop -m python/Cargo.toml +- Python deps: pyarrow + +Run: + python examples/kg_traversal.py +""" + +from __future__ import annotations + +import pyarrow as pa + +from lance_graph import GraphConfigBuilder, CypherQuery + + +def make_people_batch(n: int = 6) -> pa.RecordBatch: + return pa.record_batch( + [ + pa.array(list(range(1, n + 1)), type=pa.int32()), + pa.array([f"P{i}" for i in range(1, n + 1)], type=pa.string()), + ], + names=["person_id", "name"], + ) + + +def make_friendship_batch(n: int = 6) -> pa.RecordBatch: + # Create a simple ring: 1->2->3->...->n->1 + src = list(range(1, n + 1)) + dst = [i + 1 if i < n else 1 for i in src] + return pa.record_batch( + [pa.array(src, type=pa.int32()), pa.array(dst, type=pa.int32())], + names=["person1_id", "person2_id"], + ) + + +def main() -> None: + config = ( + GraphConfigBuilder() + .with_node_label("Person", "person_id") + .with_relationship("FRIEND_OF", "person1_id", "person2_id") + .build() + ) + + # Two-hop traversal from a person to friend-of-a-friend + query = ( + CypherQuery( + "MATCH (a:Person)-[:FRIEND_OF]->(b:Person)-[:FRIEND_OF]->(c:Person) RETURN a.name, c.name" + ) + .with_config(config) + ) + + datasets = { + "Person": make_people_batch(), + "FRIEND_OF": make_friendship_batch(), + } + result = query.execute(datasets) + print(result.to_pydict()) + + +if __name__ == "__main__": + main() diff --git a/python/src/executor.rs b/python/src/executor.rs index d4be02d8..affd4be6 100644 --- a/python/src/executor.rs +++ b/python/src/executor.rs @@ -31,6 +31,7 @@ pub struct BackgroundExecutor { } impl BackgroundExecutor { + #[allow(dead_code)] pub fn get_runtime_handle(&self) -> Option { Some(self.runtime.handle().clone()) } @@ -50,6 +51,7 @@ impl BackgroundExecutor { /// /// This method is safe to use with inputs that may reference a Rust async /// runtime. + #[allow(dead_code)] pub fn spawn(&self, py: Option>, task: T) -> PyResult where T: Future + Send + 'static, @@ -63,6 +65,7 @@ impl BackgroundExecutor { } } + #[allow(dead_code)] fn spawn_impl(&self, task: T) -> PyResult where T: Future + Send + 'static, @@ -103,6 +106,7 @@ impl BackgroundExecutor { } /// Spawn a task in the background + #[allow(dead_code)] pub fn spawn_background(&self, py: Option>, task: T) where T: Future + Send + 'static, diff --git a/rust/lance-graph/README.md b/rust/lance-graph/README.md index 137a5311..757e59d1 100644 --- a/rust/lance-graph/README.md +++ b/rust/lance-graph/README.md @@ -164,6 +164,33 @@ Numbers are illustrative; your hardware, compiler, and runtime load will affect Python bindings for this crate live under `python/src/graph.rs` and expose the same configuration and query APIs via PyO3. +### Python Examples + +See top-level `examples/` for runnable Python examples: + +- `basic_cypher.py`: simple node filter and projection against in-memory Arrow batches. +- `kg_traversal.py`: two-hop traversal on a small synthetic knowledge graph. + +Setup and run (from repo root): + +```bash +Option A - Local build (editable): + +```bash +maturin develop -m python/Cargo.toml +python examples/basic_cypher.py +python examples/kg_traversal.py +``` + +Option B - Using uv: + +```bash +uvx --from maturin maturin develop -m python/Cargo.toml +uv run --with pyarrow python examples/basic_cypher.py +uv run --with pyarrow python examples/kg_traversal.py +``` +``` + ## License Apache-2.0. See the top-level LICENSE file for details.