Pipeline query engine over semi-structured text: CSV, JSON, logfmt, access logs and syslog in, query plans, indexes and aggregations out
Dependencies
$ moonloom query --file examples/access.log --stats \
"where status >= 500 | stats count() as failures by path | sort failures desc"
+--------------------+----------+
| path | failures |
+--------------------+----------+
| /api/orders?page=2 | 2 |
| /api/orders?page=1 | 1 |
| /health | 1 |
+--------------------+----------+
rows in 21, scanned 21, filtered 17, groups 3, out 3moon check --target all
moon build --target wasm
moon test --deny-warn --target wasm
moon run examples/demo # a self-contained tour, no files needed
moon run --target js cmd/main -- query --file examples/access.log \
"where status >= 500 | stats count() as n by path | sort n desc"from <name> | where ... | stats ... | sort ... | limit ...| Stage | Meaning |
|---|---|
| where <expr> / filter | keep the rows the expression accepts |
| fields a, b / select | keep and order these columns |
| eval name = <expr> | add or replace a column |
| parse "pattern" | extract named fields from the source line |
| stats agg, agg by a, b | group and aggregate |
| sort a desc, b asc / order | order rows |
| limit n / head | keep the first n rows |
| top n by <key> | order and cut in one step |
| dedup a, b / distinct | keep the first row per key |
# sales: revenue per region, largest first
moon run --target js cmd/main -- query --file examples/sales.csv --output markdown \
"stats sum(amount) as revenue by region | sort revenue desc"
# JSON Lines: nested objects become dotted field names
moon run --target js cmd/main -- query --file examples/events.jsonl \
"where http.status >= 500 | stats count() as n, percentile(duration_ms, 95) as p95 by service"
# plain text: a pattern turns prose into columns
moon run --target js cmd/main -- query --file examples/service.log --format lines \
"parse \"{time} {level} {service}: {message}\" | where level == \"error\""| Reader | Accepts |
|---|---|
| csv / tsv | RFC 4180 delimited text; the delimiter is guessed from , ; \t | and quoted fields may contain it, doubled quotes and line breaks |
| json | one document: an array of objects, or a single object |
| jsonl | one JSON value per line; nested objects become a.b, arrays become a.0 |
| logfmt | key=value, quoted values, bare flags |
| keyvalue | key: value or key = value, with [section] headers and # comments |
| access | Common and Combined Log Format, with the request split into method, path and protocol |
| syslog | RFC 3164 and RFC 5424, with facility and severity decoded from the priority |
| lines | one record per line, with a single line field |
$ moonloom schema --file examples/events.jsonl
format jsonl records 10 skipped 0
+-------------+------+---------+---------+----------+
| name | kind | present | missing | distinct |
+-------------+------+---------+---------+----------+
| time | text | 10 | 0 | 9 |
| level | text | 10 | 0 | 3 |
| duration_ms | num | 10 | 0 | 10 |
| http.status | int | 10 | 0 | 6 |
...$ moonloom explain --file examples/access.log \
"where remote_host == \"203.0.113.51\" | fields time_text, method, path, status"
plan
scan <input>
rows=21
index remote_host=203.0.113.51 kept=3/21 (14.3%)
1. filter remote_host == "203.0.113.51"
2. project time_text, method, path, status
columns remote_host, time_text, method, path, status$ moonloom query --file examples/access.log --stats "where status >= 500 | stats count() as n by path"
...
rows in 21, scanned 21, filtered 17, groups 3, out 3| Package | What it provides |
|---|---|
| haol-05/moonloom | Value, Record, Table, Dataset, diagnostics, schema inference, number parsing |
| .../ascii | code-unit predicates and lexicographic text comparison |
| .../text | the readers plus timestamp and duration parsing |
| .../query | tokens, syntax tree and the parser |
| .../index | inverted index and candidate pruning |
| .../plan | plan construction and explain |
| .../exec | expression evaluation, aggregation and the operators |
| .../render | aligned table and JSON / JSON Lines / CSV / Markdown exports |
match @exec.query_text(source, "where level == \"error\" | stats count() as n by service") {
Ok(result) => println(@render.render_table(result))
Err(message) => println("query error: " + message)
}let dataset = @text.parse_auto(source, format="logfmt")
let query = @query.Query::parse(text).unwrap()
let index = @index.TableIndex::build(dataset.table)
let plan = @plan.compile(query, dataset.table, Some(index))
println(plan.explain())
let result = @exec.run(query, dataset.table, Some(index))moon version --all
moon check --deny-warn --target all
moon build --target wasm
moon test --deny-warn --target wasm
moon test --deny-warn --target wasm-gc
moon test --deny-warn --target js
moon fmt && git diff --exit-code
moon info && git diff --exit-code
moon run --target wasm examples/demofn escape_json(s : String) -> Stringfn format_double(d : Double) -> StringInstall
Download zipPipeline query engine over semi-structured text: CSV, JSON, logfmt, access logs and syslog in, query plans, indexes and aggregations out
Dependencies