Moteur JSONPath expérimental pour interroger des ensembles de données diffusés en continu massifs.
La caisse rsonpath
fournit un analyseur JSONPath et un moteur d'exécution de requêtes rq
, qui utilise les instructions SIMD pour fournir des améliorations massives du débit par rapport aux moteurs conventionnels.
Benchmarks de rsonpath
par rapport à un moteur de référence sans SIMD sur l'ensemble de données Pison. REMARQUE : L'échelle est logarithmique !
Pour exécuter une requête JSONPath sur un fichier, exécutez :
rq '$..a.b' ./file.json
Si le fichier est omis, le moteur lit l'entrée standard. JSON peut également être transmis en ligne :
$ rq ' $..a.b ' --json ' {"c":{"a":{"b":42}}} '
42
Pour plus de détails, consultez rq --help
ou le rsonbook.
Le résultat de l’exécution d’une requête est une séquence de valeurs correspondantes, délimitées par des nouvelles lignes. Alternativement, passer --result count
renvoie uniquement le nombre de correspondances, ce qui peut être beaucoup plus rapide. Pour d'autres modes de résultat, consultez la page d'utilisation --help
.
Voir les versions pour les binaires précompilés pour toutes les cibles de support de première classe.
cargo
Le moyen le plus simple d'installer est via cargo
.
$ cargo install rsonpath
...
Si la vitesse maximale est primordiale, vous devez installer rsonpath
avec la prise en charge native des instructions CPU. Cela se traduira par un binaire qui n'est pas portable et pourrait ne pas fonctionner correctement sur n'importe quelle autre machine, mais cela réduira jusqu'au dernier bit de débit.
Pour ce faire, exécutez la variante cargo install
suivante :
$ RUSTFLAGS= " -C target-cpu=native " cargo install rsonpath
...
Consultez le chapitre correspondant dans le rsonbook.
Le projet est activement développé et ne prend actuellement en charge qu'un sous-ensemble du langage de requête JSONPath. Une requête est une séquence de segments, chacun contenant un ou plusieurs sélecteurs.
Segment | Syntaxe | Soutenu | Depuis | Problème de suivi |
---|---|---|---|---|
Segment enfant (simple) | [<selector>] | ✔️ | v0.1.0 | |
Segment enfant (multiple) | [<selector1>,...,<selectorN>] | |||
Segment descendant (célibataire) | ..[<selector>] | ✔️ | v0.1.0 | |
Segment descendant (multiple) | ..[<selector1>,...,<selectorN>] |
Sélecteur | Syntaxe | Soutenu | Depuis | Problème de suivi |
---|---|---|---|---|
Racine | $ | ✔️ | v0.1.0 | |
Nom | .<member> , [<member>] | ✔️ | v0.1.0 | |
Caractère générique | .* , ..* , [*] | ✔️ | v0.4.0 | |
Index (index de tableau) | [<index>] | ✔️ | v0.5.0 | |
Index (index du tableau à partir de la fin) | [-<index>] | |||
Tranche de tableau (vers l'avant, limites positives) | [<start>:<end>:<step>] | ✔️ | v0.9.0 | #152 |
Tranche de tableau (vers l'avant, limites arbitraires) | [<start>:<end>:<step>] | |||
Tranche de tableau (en arrière, limites arbitraires) | [<start>:<end>:-<step>] | |||
Filtres – tests existentiels | [?<path>] | #154 | ||
Filtres – comparaisons d’atomes const | [?<path> <binop> <atom>] | #156 | ||
Filtres – expressions logiques | && , || , ! | |||
Filtres – imbrication | [?<expr>[?<expr>]...] | |||
Filtres – comparaisons arbitraires | [?<path> <binop> <path>] | |||
Filtres – extensions de fonctions | [?func(<path>)] |
La caisse est construite en permanence pour toutes les cibles Rust de niveau 1, et des tests sont exécutés en permanence pour les cibles pouvant être exécutées avec des images d'action GitHub. SIMD est pris en charge uniquement sur les plates-formes x86/x86_64.
Objectif triple | construction nosimd | Prise en charge SIMD | Tests continus | Problèmes de suivi |
---|---|---|---|---|
aarch64-inconnu-linux-gnu | ✔️ | ✔️ | #21, #115 | |
i686-inconnu-linux-gnu | ✔️ | ✔️ | ✔️ | |
x86_64-inconnu-linux-gnu | ✔️ | ✔️ | ✔️ | |
x86_64-apple-darwin | ✔️ | ✔️ | ✔️ | |
i686-pc-windows-gnu | ✔️ | ✔️ | ✔️ | |
i686-pc-windows-msvc | ✔️ | ✔️ | ✔️ | |
x86_64-pc-windows-gnu | ✔️ | ✔️ | ✔️ | |
x86_64-pc-windows-msvc | ✔️ | ✔️ | ✔️ |
La prise en charge SIMD est activée module par module. Généralement, tout processeur sorti au cours de la dernière décennie prend en charge AVX2, qui permet toutes les optimisations disponibles.
Les processeurs plus anciens avec SSE2 ou supérieur bénéficient d'une prise en charge partielle. Vous pouvez vérifier exactement ce qui est activé avec rq --version
– vérifiez le champ SIMD support
:
$ rq --version
rq 0.9.1
Commit SHA: c024e1bab89610455537b77aed249d2a05a81ed6
Features: default,simd
Opt level: 3
Target triple: x86_64-unknown-linux-gnu
Codegen flags: link-arg=-fuse-ld=lld
SIMD support: avx2;fast_quotes;fast_popcnt
La capacité fast_quotes
dépend de l'instruction pclmulqdq
et fast_popcnt
de l'instruction popcnt
.
Tous les sélecteurs ne sont pas pris en charge, voir le tableau de prise en charge ci-dessus.
Le moteur suppose que chaque objet du JSON d'entrée n'a pas de clés en double. Il n'est pas garanti que le comportement des clés en double soit stable, mais actuellement, le moteur correspondra simplement à la première clé de ce type.
$ rq ' $.key ' --json ' {"key":"value","key":"other value"} '
"value"
Le moteur n'analyse pas les séquences d'échappement Unicode dans les noms de membres. Cela signifie qu'une clé "a"
est différente d'une clé "u0041"
, même si sémantiquement elles représentent la même chaîne. Ceci est en fait tel que conçu par rapport à la spécification JSONPath actuelle. L'analyse des séquences Unicode est coûteuse, c'est pourquoi sa prise en charge a été reportée au profit de hautes performances. Ceci est suivi comme #117.
L'essentiel est le suivant : fork, implémentez, faites un PR ici. Plus de détails sont dans le document CONTRIBUANT.
Le workflow de développement utilise just
. Utilisez le Justfile
inclus. Il installera automatiquement Rust pour vous à l'aide de l'outil rustup
s'il détecte qu'il n'y a pas de Cargo dans votre environnement.
$ just build
...
$ just test
...
Les benchmarks pour rsonpath
se trouvent dans un référentiel séparé, inclus en tant que sous-module git dans ce référentiel principal.
Le moyen le plus simple d'exécuter tous les benchmarks est just bench
. Pour plus de détails, consultez le README dans le sous-module.
Nous avons un article sur rsonpath
qui sera publié à l'ASPLOS '24 ! Vous pouvez le lire ici.
Ce projet a été conçu comme ma thèse. Vous pouvez le lire pour plus de détails sur le contexte théorique du moteur et les détails de sa mise en œuvre.
Affichage des dépendances directes, pour le graphique complet, voir ci-dessous.
cargo tree --package rsonpath --edges normal --depth 1
rsonpath v0.9.1 (/home/mat/src/rsonpath/crates/rsonpath)
├── clap v4.5.4
├── color-eyre v0.6.3
├── eyre v0.6.12
├── log v0.4.21
├── rsonpath-lib v0.9.1 (/home/mat/src/rsonpath/crates/rsonpath-lib)
├── rsonpath-syntax v0.3.1 (/home/mat/src/rsonpath/crates/rsonpath-syntax)
└── simple_logger v4.3.3
[build-dependencies]
├── rustflags v0.1.5
└── vergen v8.3.1
[build-dependencies]
cargo tree --package rsonpath-lib --edges normal --depth 1
rsonpath-lib v0.9.1 (/home/mat/src/rsonpath/crates/rsonpath-lib)
├── arbitrary v1.3.2
├── cfg-if v1.0.0
├── log v0.4.21
├── memmap2 v0.9.4
├── nom v7.1.3
├── rsonpath-syntax v0.3.1 (/home/mat/src/rsonpath/crates/rsonpath-syntax)
├── smallvec v1.13.2
├── static_assertions v1.1.0
├── thiserror v1.0.58
└── vector-map v1.0.1
clap
– caisse standard pour fournir la CLI.color-eyre
, eyre
– messages d'erreur plus accessibles pour l'analyseur.log
, simple-logger
– journaux de diagnostic pendant la compilation et l'exécution.cfg-if
– utilisé pour prendre en charge les versions SIMD et non-SIMD.memmap2
– pour une lecture rapide des fichiers sources via une carte mémoire au lieu de copies mises en mémoire tampon.nom
– pour l’implémentation de l’analyseur.smallvec
– crucial pour les performances des petites piles.static_assertions
– fiabilité supplémentaire grâce à certaines hypothèses constantes validées au moment de la compilation.thiserror
– implémentations Error
idiomatiques.vector_map
– utilisé dans le compilateur de requêtes pour des performances nettement meilleures. cargo tree --package rsonpath --edges normal
rsonpath v0.9.1 (/home/mat/src/rsonpath/crates/rsonpath)
├── clap v4.5.4
│ ├── clap_builder v4.5.2
│ │ ├── anstream v0.6.13
│ │ │ ├── anstyle v1.0.6
│ │ │ ├── anstyle-parse v0.2.3
│ │ │ │ └── utf8parse v0.2.1
│ │ │ ├── anstyle-query v1.0.2
│ │ │ │ └── windows-sys v0.52.0
│ │ │ │ └── windows-targets v0.52.4
│ │ │ │ ├── windows_aarch64_gnullvm v0.52.4
│ │ │ │ ├── windows_aarch64_msvc v0.52.4
│ │ │ │ ├── windows_i686_gnu v0.52.4
│ │ │ │ ├── windows_i686_msvc v0.52.4
│ │ │ │ ├── windows_x86_64_gnu v0.52.4
│ │ │ │ ├── windows_x86_64_gnullvm v0.52.4
│ │ │ │ └── windows_x86_64_msvc v0.52.4
│ │ │ ├── anstyle-wincon v3.0.2
│ │ │ │ ├── anstyle v1.0.6
│ │ │ │ └── windows-sys v0.52.0 (*)
│ │ │ ├── colorchoice v1.0.0
│ │ │ └── utf8parse v0.2.1
│ │ ├── anstyle v1.0.6
│ │ ├── clap_lex v0.7.0
│ │ ├── strsim v0.11.1
│ │ └── terminal_size v0.3.0
│ │ ├── rustix v0.38.32
│ │ │ ├── bitflags v2.5.0
│ │ │ ├── errno v0.3.8
│ │ │ │ ├── libc v0.2.153
│ │ │ │ └── windows-sys v0.52.0 (*)
│ │ │ ├── libc v0.2.153
│ │ │ ├── linux-raw-sys v0.4.13
│ │ │ └── windows-sys v0.52.0 (*)
│ │ └── windows-sys v0.48.0
│ │ └── windows-targets v0.48.5
│ │ ├── windows_aarch64_gnullvm v0.48.5
│ │ ├── windows_aarch64_msvc v0.48.5
│ │ ├── windows_i686_gnu v0.48.5
│ │ ├── windows_i686_msvc v0.48.5
│ │ ├── windows_x86_64_gnu v0.48.5
│ │ ├── windows_x86_64_gnullvm v0.48.5
│ │ └── windows_x86_64_msvc v0.48.5
│ └── clap_derive v4.5.4 (proc-macro)
│ ├── heck v0.5.0
│ ├── proc-macro2 v1.0.79
│ │ └── unicode-ident v1.0.12
│ ├── quote v1.0.35
│ │ └── proc-macro2 v1.0.79 (*)
│ └── syn v2.0.58
│ ├── proc-macro2 v1.0.79 (*)
│ ├── quote v1.0.35 (*)
│ └── unicode-ident v1.0.12
├── color-eyre v0.6.3
│ ├── backtrace v0.3.71
│ │ ├── addr2line v0.21.0
│ │ │ └── gimli v0.28.1
│ │ ├── cfg-if v1.0.0
│ │ ├── libc v0.2.153
│ │ ├── miniz_oxide v0.7.2
│ │ │ └── adler v1.0.2
│ │ ├── object v0.32.2
│ │ │ └── memchr v2.7.2
│ │ └── rustc-demangle v0.1.23
│ │ [build-dependencies]
│ │ └── cc v1.0.90
│ ├── eyre v0.6.12
│ │ ├── indenter v0.3.3
│ │ └── once_cell v1.19.0
│ ├── indenter v0.3.3
│ ├── once_cell v1.19.0
│ └── owo-colors v3.5.0
├── eyre v0.6.12 (*)
├── log v0.4.21
├── rsonpath-lib v0.9.1 (/home/mat/src/rsonpath/crates/rsonpath-lib)
│ ├── cfg-if v1.0.0
│ ├── log v0.4.21
│ ├── memmap2 v0.9.4
│ │ └── libc v0.2.153
│ ├── nom v7.1.3
│ │ ├── memchr v2.7.2
│ │ └── minimal-lexical v0.2.1
│ ├── rsonpath-syntax v0.3.1 (/home/mat/src/rsonpath/crates/rsonpath-syntax)
│ │ ├── nom v7.1.3 (*)
│ │ ├── owo-colors v4.0.0
│ │ ├── thiserror v1.0.58
│ │ │ └── thiserror-impl v1.0.58 (proc-macro)
│ │ │ ├── proc-macro2 v1.0.79 (*)
│ │ │ ├── quote v1.0.35 (*)
│ │ │ └── syn v2.0.58 (*)
│ │ └── unicode-width v0.1.11
│ ├── smallvec v1.13.2
│ ├── static_assertions v1.1.0
│ ├── thiserror v1.0.58 (*)
│ └── vector-map v1.0.1
│ ├── contracts v0.4.0 (proc-macro)
│ │ ├── proc-macro2 v1.0.79 (*)
│ │ ├── quote v1.0.35 (*)
│ │ └── syn v1.0.109
│ │ ├── proc-macro2 v1.0.79 (*)
│ │ ├── quote v1.0.35 (*)
│ │ └── unicode-ident v1.0.12
│ └── rand v0.7.3
│ ├── getrandom v0.1.16
│ │ ├── cfg-if v1.0.0
│ │ ├── libc v0.2.153
│ │ └── wasi v0.9.0+wasi-snapshot-preview1
│ ├── libc v0.2.153
│ ├── rand_chacha v0.2.2
│ │ ├── ppv-lite86 v0.2.17
│ │ └── rand_core v0.5.1
│ │ └── getrandom v0.1.16 (*)
│ ├── rand_core v0.5.1 (*)
│ └── rand_hc v0.2.0
│ └── rand_core v0.5.1 (*)
├── rsonpath-syntax v0.3.1 (/home/mat/src/rsonpath/crates/rsonpath-syntax) (*)
└── simple_logger v4.3.3
├── colored v2.1.0
│ ├── lazy_static v1.4.0
│ └── windows-sys v0.48.0 (*)
├── log v0.4.21
├── time v0.3.34
│ ├── deranged v0.3.11
│ │ └── powerfmt v0.2.0
│ ├── itoa v1.0.11
│ ├── libc v0.2.153
│ ├── num-conv v0.1.0
│ ├── num_threads v0.1.7
│ │ └── libc v0.2.153
│ ├── powerfmt v0.2.0
│ ├── time-core v0.1.2
│ └── time-macros v0.2.17 (proc-macro)
│ ├── num-conv v0.1.0
│ └── time-core v0.1.2
└── windows-sys v0.48.0 (*)
[build-dependencies]
├── rustflags v0.1.5
└── vergen v8.3.1
├── anyhow v1.0.81
├── cargo_metadata v0.18.1
│ ├── camino v1.1.6
│ │ └── serde v1.0.197
│ │ └── serde_derive v1.0.197 (proc-macro)
│ │ ├── proc-macro2 v1.0.79 (*)
│ │ ├── quote v1.0.35 (*)
│ │ └── syn v2.0.58 (*)
│ ├── cargo-platform v0.1.8
│ │ └── serde v1.0.197 (*)
│ ├── semver v1.0.22
│ │ └── serde v1.0.197 (*)
│ ├── serde v1.0.197 (*)
│ ├── serde_json v1.0.115
│ │ ├── itoa v1.0.11
│ │ ├── ryu v1.0.17
│ │ └── serde v1.0.197 (*)
│ └── thiserror v1.0.58 (*)
├── cfg-if v1.0.0
├── regex v1.10.4
│ ├── aho-corasick v1.1.3
│ │ └── memchr v2.7.2
│ ├── memchr v2.7.2
│ ├── regex-automata v0.4.6
│ │ ├── aho-corasick v1.1.3 (*)
│ │ ├── memchr v2.7.2
│ │ └── regex-syntax v0.8.3
│ └── regex-syntax v0.8.3
├── rustc_version v0.4.0
│ └── semver v1.0.22 (*)
└── time v0.3.34
├── deranged v0.3.11 (*)
├── itoa v1.0.11
├── libc v0.2.153
├── num-conv v0.1.0
├── num_threads v0.1.7 (*)
├── powerfmt v0.2.0
└── time-core v0.1.2
[build-dependencies]
└── rustversion v1.0.14 (proc-macro)