|
1 | 1 | # Janus |
2 | 2 |
|
3 | | -Janus is a hybrid engine for unified Live and Historical RDF Stream Processing, implemented in Rust. |
| 3 | +Janus is a Rust engine for unified historical and live RDF stream processing. |
| 4 | + |
| 5 | +It combines: |
| 6 | + |
| 7 | +- historical window evaluation over segmented RDF storage |
| 8 | +- live window evaluation over incoming streams |
| 9 | +- a single Janus-QL query model for hybrid queries |
| 10 | +- an HTTP/WebSocket API for query lifecycle management and result delivery |
| 11 | + |
| 12 | +The name comes from the Roman deity Janus, associated with transitions and with looking both backward and forward. That dual perspective matches Janus's goal: querying past and live RDF data together. |
| 13 | + |
| 14 | +## What Janus Supports |
| 15 | + |
| 16 | +- Historical windows with `START` / `END` |
| 17 | +- Sliding live windows with `RANGE` / `STEP` |
| 18 | +- Hybrid queries that mix historical and live windows |
| 19 | +- Extension functions for anomaly-style predicates such as thresholds, relative change, z-score, outlier checks, and trend divergence |
| 20 | +- Optional baseline bootstrapping for hybrid anomaly queries with `USING BASELINE <window> LAST|AGGREGATE` |
| 21 | +- HTTP endpoints for registering, starting, stopping, listing, and deleting queries |
| 22 | +- WebSocket result streaming for running queries |
| 23 | + |
| 24 | +## Query Model |
| 25 | + |
| 26 | +Janus uses Janus-QL, a hybrid query language for querying historical and live RDF data in one query. |
| 27 | + |
| 28 | +Example: |
| 29 | + |
| 30 | +```sparql |
| 31 | +PREFIX ex: <http://example.org/> |
| 32 | +PREFIX janus: <https://janus.rs/fn#> |
| 33 | +PREFIX baseline: <https://janus.rs/baseline#> |
| 34 | +
|
| 35 | +REGISTER RStream ex:out AS |
| 36 | +SELECT ?sensor ?reading |
| 37 | +FROM NAMED WINDOW ex:hist ON LOG ex:store [START 1700000000000 END 1700003600000] |
| 38 | +FROM NAMED WINDOW ex:live ON STREAM ex:stream1 [RANGE 5000 STEP 1000] |
| 39 | +USING BASELINE ex:hist AGGREGATE |
| 40 | +WHERE { |
| 41 | + WINDOW ex:hist { |
| 42 | + ?sensor ex:mean ?mean . |
| 43 | + ?sensor ex:sigma ?sigma . |
| 44 | + } |
| 45 | + WINDOW ex:live { |
| 46 | + ?sensor ex:hasReading ?reading . |
| 47 | + } |
| 48 | + ?sensor baseline:mean ?mean . |
| 49 | + ?sensor baseline:sigma ?sigma . |
| 50 | + FILTER(janus:is_outlier(?reading, ?mean, ?sigma, 3)) |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +`USING BASELINE` is optional. If present, Janus bootstraps baseline values from the named historical window before or during live execution: |
4 | 55 |
|
5 | | -The name "Janus" is inspired by the Roman deity Janus who is the guardian of doorways and transitions, and looks towards both the past and the future simultaneously. This dual perspective reflects Janus's capability to process both Historical and Live RDF streams in a unified manner utilizing a single query language and engine. |
| 56 | +- `LAST`: use the final historical window snapshot as baseline |
| 57 | +- `AGGREGATE`: merge the historical window outputs into one compact baseline |
6 | 58 |
|
7 | 59 | ## Performance |
8 | 60 |
|
9 | | -Janus achieves high-throughput RDF stream processing with dictionary encoding and streaming segmented storage: |
| 61 | +Janus uses dictionary encoding and segmented storage for high-throughput ingestion and historical reads. |
10 | 62 |
|
11 | | -- Write Throughput: 2.6-3.14 Million quads/sec |
12 | | -- Read Throughput: 2.7-2.77 Million quads/sec |
13 | | -- Point Query Latency: Sub-millisecond (0.235 ms at 1M quads) |
14 | | -- Space Efficiency: 40% reduction through dictionary encoding (24 bytes vs 40 bytes per event) |
| 63 | +- Write throughput: 2.6-3.14 million quads/sec |
| 64 | +- Read throughput: 2.7-2.77 million quads/sec |
| 65 | +- Point query latency: 0.235 ms at 1M quads |
| 66 | +- Space efficiency: about 40% smaller encoded events |
15 | 67 |
|
16 | | -For detailed benchmark results, see [BENCHMARK_RESULTS.md](./BENCHMARK_RESULTS.md). |
| 68 | +Detailed benchmark data is in [BENCHMARK_RESULTS.md](./BENCHMARK_RESULTS.md). |
17 | 69 |
|
18 | | -## Development |
| 70 | +## Quick Start |
19 | 71 |
|
20 | 72 | ### Prerequisites |
21 | 73 |
|
22 | | -- Rust (stable toolchain) |
| 74 | +- Rust stable |
23 | 75 | - Cargo |
24 | 76 |
|
25 | | -### Building |
| 77 | +### Build |
26 | 78 |
|
27 | 79 | ```bash |
28 | | -# Debug build |
29 | 80 | make build |
30 | | - |
31 | | -# Release build (optimized) |
32 | 81 | make release |
33 | 82 | ``` |
34 | 83 |
|
35 | | -### Testing |
| 84 | +### Run the HTTP API |
36 | 85 |
|
37 | 86 | ```bash |
38 | | -# Run all tests |
39 | | -make test |
40 | | - |
41 | | -# Run tests with verbose output |
42 | | -make test-verbose |
| 87 | +cargo run --bin http_server -- --host 127.0.0.1 --port 8080 --storage-dir ./data/storage |
43 | 88 | ``` |
44 | 89 |
|
45 | | -### Code Quality |
| 90 | +Then check the server: |
46 | 91 |
|
47 | | -Before pushing to the repository, run the CI/CD checks locally: |
| 92 | +```bash |
| 93 | +curl http://127.0.0.1:8080/health |
| 94 | +``` |
| 95 | + |
| 96 | +### Try the HTTP client example |
48 | 97 |
|
49 | 98 | ```bash |
50 | | -# Run all CI/CD checks (formatting, linting, tests, build) |
51 | | -make ci-check |
| 99 | +cargo run --example http_client_example |
| 100 | +``` |
52 | 101 |
|
53 | | -# Or use the script directly |
54 | | - ./scripts/ci-check.sh``` |
| 102 | +This example demonstrates: |
55 | 103 |
|
56 | | -This will run: |
57 | | -- **rustfmt** - Code formatting check |
58 | | -- **clippy** - Lint checks with warnings as errors |
59 | | -- **tests** - Full test suite |
60 | | -- **build** - Compilation check |
| 104 | +- query registration |
| 105 | +- query start and stop |
| 106 | +- query inspection |
| 107 | +- replay control |
| 108 | +- WebSocket result consumption |
61 | 109 |
|
62 | | -Individual checks can also be run: |
| 110 | +## Development |
| 111 | + |
| 112 | +### Common Commands |
63 | 113 |
|
64 | 114 | ```bash |
65 | | -make fmt # Format code |
66 | | -make fmt-check # Check formatting |
67 | | -make lint # Run Clippy |
68 | | -make check # Run formatting and linting checks |
| 115 | +make build # debug build |
| 116 | +make release # optimized build |
| 117 | +make test # full test suite |
| 118 | +make test-verbose # verbose tests |
| 119 | +make fmt # format code |
| 120 | +make fmt-check # check formatting |
| 121 | +make lint # clippy with warnings as errors |
| 122 | +make check # formatting + linting |
| 123 | +make ci-check # local CI script |
69 | 124 | ``` |
70 | 125 |
|
71 | | -## Licence |
| 126 | +### Examples |
72 | 127 |
|
73 | | -This code is copyrighted by Ghent University - imec and released under the MIT Licence |
| 128 | +The repository includes runnable examples under [`examples/`](./examples), including: |
74 | 129 |
|
75 | | -## Contact |
| 130 | +- [`examples/http_client_example.rs`](./examples/http_client_example.rs) |
| 131 | +- [`examples/comparator_demo.rs`](./examples/comparator_demo.rs) |
| 132 | +- [`examples/demo_dashboard.html`](./examples/demo_dashboard.html) |
| 133 | + |
| 134 | +## Project Layout |
76 | 135 |
|
77 | | -For any questions, please contact [Kush](mailto:mailkushbisen@gmail.com) or create an issue in the repository. |
| 136 | +- [`src/api`](./src/api): query lifecycle and orchestration |
| 137 | +- [`src/parsing`](./src/parsing): Janus-QL parsing |
| 138 | +- [`src/stream`](./src/stream): live stream processing |
| 139 | +- [`src/execution`](./src/execution): historical execution |
| 140 | +- [`src/storage`](./src/storage): segmented RDF storage |
| 141 | +- [`src/http`](./src/http): REST and WebSocket API |
| 142 | +- [`tests`](./tests): integration and parser coverage |
| 143 | + |
| 144 | +## License |
| 145 | + |
| 146 | +This project is released under the MIT License. |
| 147 | + |
| 148 | +## Contact |
78 | 149 |
|
79 | | ---- |
| 150 | +For questions, open an issue or contact [Kush](mailto:mailkushbisen@gmail.com). |
0 commit comments