Skip to content

Commit d9336c1

Browse files
committed
Add 3DGS Lance Arrow storage plan
1 parent e369a72 commit d9336c1

1 file changed

Lines changed: 208 additions & 0 deletions

File tree

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# 3DGS Lance/Arrow Storage Plan — lance-graph
2+
3+
## Goal
4+
5+
Define durable Lance/Arrow schemas for 3DGS geospatial content.
6+
7+
The storage model must support:
8+
9+
- 3D Tiles hierarchy
10+
- implicit tiling metadata
11+
- 3DGS splat block metadata
12+
- feature and asset overlays
13+
- error certificates
14+
- query and traversal planning
15+
- future ArcGIS/Cesium compatibility exports
16+
17+
## Core tables
18+
19+
### `tiles`
20+
21+
One row per tile node.
22+
23+
```text
24+
tile_id: Utf8
25+
parent_tile_id: Utf8?
26+
level: UInt32
27+
x: UInt64?
28+
y: UInt64?
29+
z: UInt64?
30+
morton: UInt64?
31+
refine_mode: Utf8
32+
geometric_error_m: Float32
33+
bounding_volume_type: Utf8
34+
bounding_volume_values: FixedSizeList<Float64>
35+
content_count: UInt32
36+
metadata_id: Utf8?
37+
```
38+
39+
### `contents`
40+
41+
One row per tile content payload.
42+
43+
```text
44+
content_id: Utf8
45+
tile_id: Utf8
46+
content_kind: Utf8
47+
uri: Utf8
48+
media_type: Utf8?
49+
byte_size: UInt64?
50+
feature_count: UInt64?
51+
splat_count: UInt64?
52+
codec: Utf8?
53+
certificate_id: Utf8?
54+
```
55+
56+
### `subtrees`
57+
58+
For implicit tiling.
59+
60+
```text
61+
subtree_id: Utf8
62+
root_tile_id: Utf8
63+
subtree_levels: UInt32
64+
tile_availability_kind: Utf8
65+
content_availability_kind: Utf8
66+
child_subtree_availability_kind: Utf8
67+
tile_availability_bytes: Binary?
68+
content_availability_bytes: Binary?
69+
child_subtree_availability_bytes: Binary?
70+
```
71+
72+
### `splat_blocks`
73+
74+
One row per 3DGS block, not per splat.
75+
76+
```text
77+
block_id: Utf8
78+
content_id: Utf8
79+
tile_id: Utf8
80+
splat_count: UInt64
81+
local_origin_x: Float64
82+
local_origin_y: Float64
83+
local_origin_z: Float64
84+
bounds_min_x: Float32
85+
bounds_min_y: Float32
86+
bounds_min_z: Float32
87+
bounds_max_x: Float32
88+
bounds_max_y: Float32
89+
bounds_max_z: Float32
90+
codec: Utf8
91+
position_error_max: Float32
92+
position_error_rms: Float32
93+
scale_error_max: Float32
94+
opacity_error_max: Float32
95+
covariance_min_eigen: Float32
96+
covariance_max_eigen: Float32
97+
```
98+
99+
### `features`
100+
101+
Queryable semantic/geospatial objects.
102+
103+
```text
104+
feature_id: Utf8
105+
tile_id: Utf8
106+
content_id: Utf8?
107+
block_id: Utf8?
108+
class: Utf8?
109+
name: Utf8?
110+
asset_id: Utf8?
111+
geometry_kind: Utf8?
112+
bbox_min_x: Float64?
113+
bbox_min_y: Float64?
114+
bbox_min_z: Float64?
115+
bbox_max_x: Float64?
116+
bbox_max_y: Float64?
117+
bbox_max_z: Float64?
118+
attrs_json: Utf8?
119+
```
120+
121+
### `certificates`
122+
123+
One row per certificate.
124+
125+
```text
126+
certificate_id: Utf8
127+
scope_kind: Utf8 # tile | content | splat_block | traversal_decision
128+
scope_id: Utf8
129+
geometric_error_px: Float32?
130+
sampling_error: Float32?
131+
covariance_error: Float32?
132+
quantization_error: Float32?
133+
dependence_inflation: Float32?
134+
total_error_px: Float32?
135+
confidence: Float32?
136+
passed: Boolean
137+
failure_reasons: List<Utf8>
138+
source_pillars: List<Utf8>
139+
created_by: Utf8
140+
```
141+
142+
### `tile_decisions`
143+
144+
Optional runtime/debug table.
145+
146+
```text
147+
decision_id: Utf8
148+
camera_id: Utf8
149+
tile_id: Utf8
150+
action: Utf8
151+
priority: Float32
152+
screen_space_error_px: Float32
153+
certified_error_px: Float32?
154+
confidence: Float32?
155+
reason_codes: List<Utf8>
156+
```
157+
158+
## Design rules
159+
160+
- Store per-block splat metadata in Lance; do not store every splat as one row unless needed for debug.
161+
- Store dense splat columns as payloads or nested column chunks, not as millions of tiny rows.
162+
- Keep tile hierarchy queryable without loading payloads.
163+
- Keep certificates separate from raw tile metadata so they can be recomputed/versioned.
164+
- Use stable IDs for tiles, contents, blocks, and certificates.
165+
166+
## Query examples
167+
168+
```sql
169+
SELECT tile_id, uri
170+
FROM contents
171+
WHERE content_kind = 'GaussianSplat3d'
172+
AND splat_count > 0;
173+
```
174+
175+
```sql
176+
SELECT tile_id
177+
FROM certificates
178+
WHERE scope_kind = 'tile'
179+
AND passed = true
180+
AND confidence >= 0.995
181+
AND total_error_px < 2.0;
182+
```
183+
184+
```cypher
185+
MATCH (t:Tile)-[:HAS_CONTENT]->(c:Content)
186+
WHERE c.content_kind = 'GaussianSplat3d'
187+
RETURN t.tile_id, c.uri
188+
```
189+
190+
## Integration with existing lance-graph
191+
192+
Use DataFusion/Arrow for SQL scans and `lance-graph` graph abstractions for relationships:
193+
194+
```text
195+
Tile - HAS_CONTENT -> Content
196+
Tile - CHILD_OF -> Tile
197+
Content - HAS_SPLAT_BLOCK -> SplatBlock
198+
Tile - HAS_CERTIFICATE -> Certificate
199+
Feature - LOCATED_IN -> Tile
200+
```
201+
202+
## Acceptance criteria
203+
204+
- Schemas can be created from Rust code and written to Lance.
205+
- Queries can select tiles without loading content payloads.
206+
- Certificates can be versioned or recomputed without rewriting tile rows.
207+
- The schema supports both explicit and implicit 3D Tiles.
208+
- The schema supports 3DGS blocks as first-class content.

0 commit comments

Comments
 (0)