Skip to content

Commit c266bb7

Browse files
authored
Merge pull request #2 from linksplatform/issue-1-851865f68174
Implement Neo4j vs Doublets benchmark in Rust
2 parents ebb2aee + 44b8c84 commit c266bb7

26 files changed

+2633
-1
lines changed

.github/workflows/rust.yml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
name: Benchmark Rust version
2+
3+
on: [push, pull_request]
4+
5+
env:
6+
toolchain: nightly-2024-01-01
7+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8+
9+
jobs:
10+
benchmark:
11+
runs-on: ubuntu-latest
12+
13+
services:
14+
neo4j:
15+
image: neo4j:5.15.0
16+
env:
17+
NEO4J_AUTH: neo4j/password
18+
NEO4J_PLUGINS: '[]'
19+
options: >-
20+
--health-cmd "wget -q --spider http://localhost:7474 || exit 1"
21+
--health-interval 10s
22+
--health-timeout 10s
23+
--health-retries 10
24+
--health-start-period 30s
25+
ports:
26+
- 7474:7474
27+
- 7687:7687
28+
29+
steps:
30+
- name: Checkout repository
31+
uses: actions/checkout@v4
32+
33+
- name: Setup Rust
34+
uses: dtolnay/rust-toolchain@master
35+
with:
36+
toolchain: ${{env.toolchain}}
37+
components: rustfmt, clippy
38+
39+
- name: Wait for Neo4j to be ready
40+
run: |
41+
echo "Waiting for Neo4j to be fully ready..."
42+
for i in {1..30}; do
43+
if curl -s http://localhost:7474 > /dev/null; then
44+
echo "Neo4j is ready!"
45+
break
46+
fi
47+
echo "Attempt $i: Neo4j not ready yet..."
48+
sleep 2
49+
done
50+
51+
- name: Build benchmark
52+
run: cargo build --release --all-features --manifest-path rust/Cargo.toml
53+
54+
- name: Run benchmark
55+
working-directory: rust
56+
env:
57+
NEO4J_URI: bolt://localhost:7687
58+
NEO4J_USER: neo4j
59+
NEO4J_PASSWORD: password
60+
run: cargo bench --bench bench -- --output-format bencher | tee out.txt
61+
62+
- name: Prepare benchmark results
63+
run: |
64+
git config --global user.email "linksplatform@gmail.com"
65+
git config --global user.name "LinksPlatformBencher"
66+
cd rust
67+
pip install numpy matplotlib
68+
python3 out.py
69+
cd ..
70+
71+
# Create Docs directory if it doesn't exist
72+
mkdir -p Docs
73+
74+
# Copy generated images
75+
cp -f rust/bench_rust.png Docs/
76+
cp -f rust/bench_rust_log_scale.png Docs/
77+
78+
# Update README with latest results
79+
if [ -f rust/results.md ]; then
80+
# Replace the results section in README.md
81+
python3 -c "
82+
import re
83+
84+
with open('rust/results.md', 'r') as f:
85+
results = f.read()
86+
87+
with open('README.md', 'r') as f:
88+
readme = f.read()
89+
90+
# Pattern to find and replace the results table
91+
pattern = r'(\| Operation.*?\n\|[-|]+\n(?:\|.*?\n)*)'
92+
if re.search(pattern, readme):
93+
readme = re.sub(pattern, results.strip() + '\n', readme)
94+
95+
with open('README.md', 'w') as f:
96+
f.write(readme)
97+
"
98+
fi
99+
100+
# Commit changes if any
101+
git add Docs README.md
102+
if git diff --staged --quiet; then
103+
echo "No changes to commit"
104+
else
105+
git commit -m "Update benchmark results"
106+
git push origin HEAD
107+
fi
108+
109+
- name: Save benchmark results
110+
uses: actions/upload-artifact@v4
111+
with:
112+
name: Benchmark results
113+
path: |
114+
rust/bench_rust.png
115+
rust/bench_rust_log_scale.png
116+
rust/out.txt

Docs/bench_rust.png

46.1 KB
Loading

Docs/bench_rust_log_scale.png

45 KB
Loading

README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,48 @@
1-
# Comparisons.Neo4jVSDoublets
1+
# Comparisons.Neo4jVSDoublets
2+
3+
The comparison between Neo4j and LinksPlatform's Doublets (links) on basic database operations with links (create, read, delete, update).
4+
All benchmarks ran with 3000 links in background to increase size of indexes and 1000 are actively created/updated/deleted.
5+
6+
In this particular benchmark we decided not to increase the number of links as Neo4j will not be able to handle it at all in timeframe what GitHub Actions limit allows to use for free. Remember that to get accurate result we ran this benchmark multiple times.
7+
8+
## Task
9+
10+
Both databases used to store and retrieve doublet-links representation. To support storage, and all basic CRUD operations that provide Turing completeness for links as in [the links theory](https://habr.com/ru/articles/895896).
11+
12+
## Operations
13+
- **Create** – insert point link (link with id = source = target)
14+
- **Update** – basic link update operation
15+
- **Delete** – basic link delete operation
16+
- **Each All** – take all links matching `[*, *, *]` constraint
17+
- **Each Incoming** – take all links matching `[*, *, target]` constraint
18+
- **Each Outgoing** – take all links matching `[*, source, *]` constraint
19+
- **Each Concrete** – take all links matching `[*, source, target]` constraint
20+
- **Each Identity** – take all links matching `[id, *, *]` constraint
21+
22+
## Results
23+
The results below represent the amount of time (ns) the operation takes per iteration.
24+
- First picture shows time in a pixel scale (for doublets just minimum value is shown, otherwise it will be not present on the graph).
25+
- Second picture shows time in a logarithmic scale (to see difference clearly, because it is around 2-3 orders of magnitude).
26+
27+
### Rust
28+
![Image of Rust benchmark (pixel scale)](https://github.com/linksplatform/Comparisons.Neo4jVSDoublets/blob/main/Docs/bench_rust.png?raw=true)
29+
![Image of Rust benchmark (log scale)](https://github.com/linksplatform/Comparisons.Neo4jVSDoublets/blob/main/Docs/bench_rust_log_scale.png?raw=true)
30+
31+
### Raw benchmark results (all numbers are in nanoseconds)
32+
33+
| Operation | Doublets United Volatile | Doublets United NonVolatile | Doublets Split Volatile | Doublets Split NonVolatile | Neo4j NonTransaction | Neo4j Transaction |
34+
|---------------|--------------------------|-----------------------------|-------------------------|----------------------------|----------------------|-------------------|
35+
| Create | 99201 (0.3x faster) | 101660 (0.3x faster) | 85197 (0.4x faster) | 83516 (0.4x faster) | 3206352817 | 31808 |
36+
| Update | N/A | N/A | N/A | N/A | N/A | N/A |
37+
| Delete | N/A | N/A | N/A | N/A | 1955576426 | N/A |
38+
| Each All | N/A | N/A | N/A | N/A | N/A | N/A |
39+
| Each Identity | N/A | N/A | N/A | N/A | N/A | N/A |
40+
| Each Concrete | N/A | N/A | N/A | N/A | N/A | N/A |
41+
| Each Outgoing | N/A | N/A | N/A | N/A | N/A | N/A |
42+
| Each Incoming | N/A | N/A | N/A | N/A | N/A | N/A |
43+
44+
## Conclusion
45+
46+
The benchmark results will be automatically updated once the GitHub Actions workflow runs. Results are expected to show that Doublets significantly outperforms Neo4j in both write and read operations due to its specialized data structure for storing doublet-links.
47+
48+
To get fresh numbers, please fork the repository and rerun benchmark in GitHub Actions.

rust-toolchain.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[toolchain]
2+
channel = "nightly-2022-08-22"

0 commit comments

Comments
 (0)