Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ jobs:
matrix:
java: ["17", "21", "25"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v5
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ matrix.java }}
- uses: DeLaGuardo/setup-clojure@13.7.0
with:
# 2.13.0's bin/lein still says LEIN_VERSION 2.12.1-SNAPSHOT, so
# setup-clojure cannot install it
lein: 2.12.0
- uses: actions/cache@v4
- uses: actions/cache@v6
with:
path: ~/.m2/repository
key: m2-${{ runner.os }}-${{ hashFiles('project.clj') }}
restore-keys: m2-${{ runner.os }}-
# Embedded ZooKeeper binds port 2188 and Aeron uses /dev/shm, so the
# suite must run in a single JVM; lein test already does that.
- run: lein test
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.DS_Store
onyx.log*
*.log
resources/
outputs/
Expand Down
47 changes: 4 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,14 @@ A Clojure dataframe library for **larger-than-memory** datasets. Process million

**Add to project.clj:**
```clojure
[com.github.clojure-finance/clojask "2.0.6"]
[com.github.clojure-finance/clojask "2.1.0"]
```

**Or deps.edn:**
```clojure
com.github.clojure-finance/clojask {:mvn/version "2.0.6"}
com.github.clojure-finance/clojask {:mvn/version "2.1.0"}
```

Both also need two JVM flags, see [Requirements](#requirements).

**Basic example** (using [Employees-example.csv](test/clojask/Employees-example.csv)):
```clojure
(require '[clojask.dataframe :as ck])
Expand Down Expand Up @@ -90,44 +88,7 @@ Both also need two JVM flags, see [Requirements](#requirements).
- **OS:** macOS or Linux
- **JDK:** 17 or newer (tested on 17, 21, and 25)

**Required JVM flags:**
```clojure
;; project.clj
:jvm-opts ["--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED"
"--enable-native-access=ALL-UNNAMED"]

;; deps.edn, inside an alias (e.g. :aliases {:dev {...}}, run with -A:dev)
:jvm-opts ["--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED"
"--enable-native-access=ALL-UNNAMED"]
```

When running plain `java`, pass both flags on the command line.

The first flag is required for Agrona (used by Onyx's messaging). Without it the first `compute` fails with `IllegalAccessError: class org.agrona.UnsafeApi ... cannot access class jdk.internal.misc.Unsafe`. The second is for lz4's native code: JDK 24+ prints a warning without it, and a future JDK will block the load.

<details>
<summary><strong>Running multiple Clojask processes</strong></summary>

Each `compute` starts embedded ZooKeeper (port 2188) and Aeron (port 40200), with Aeron's files in the default media-driver directory (`/dev/shm` on Linux). To run multiple processes on one machine, give each different settings:

**System properties:**
- `clojask.zookeeper.port`
- `clojask.aeron.port`
- `clojask.aeron.dir`

**Or environment variables:**
- `CLOJASK_ZOOKEEPER_PORT`
- `CLOJASK_AERON_PORT`
- `CLOJASK_AERON_DIR`

</details>

<details>
<summary><strong>Logging</strong></summary>

Onyx writes warnings and errors to `.clojask/clojask.log` in the working directory, rotated at 10 MB with one backup.

</details>
Upgrading from 2.0.x: clojask no longer uses Onyx, so the JVM flags it needed (`--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED`, `--enable-native-access=ALL-UNNAMED`) and the `clojask.zookeeper.*` / `clojask.aeron.*` / `CLOJASK_*` port and directory settings can be removed.

## Documentation

Expand All @@ -138,7 +99,7 @@ Onyx writes warnings and errors to `.clojask/clojask.log` in the working directo

## How It Works

Clojask uses [Onyx](https://github.com/clojure-finance/onyx) (a maintained fork) as a single-machine thread pool. Operations are collected lazily and executed together when you call `compute`, streaming data through your transformation pipeline without loading the full dataset into memory.
Operations are collected lazily and executed together when you call `compute`, streaming data through your transformation pipeline without loading the full dataset into memory. Each `compute` runs in your JVM: one thread reads the input in batches, a pool of worker threads (the number you pass to `compute`) applies the operations and filters, and the calling thread writes the results in input order. Group-by and joins first sort the rows into groups by key, kept in temporary files under `.clojask/` (or in memory with `:in-memory true`); group-by and outer joins write their results in group order.

## Issues & Feedback

Expand Down
9 changes: 3 additions & 6 deletions docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ This means you cannot further apply complicated operations to a joined dataframe

#### enable-debug / disable-debug

Turn debug mode on or off. With debug mode on, operations are no longer checked against a preview when they are added, and logging is raised to `:debug`. Both take no arguments and print the new mode.
Turn debug mode on or off. With debug mode on, operations are no longer checked against a preview when they are added. Both take no arguments and print the new mode.

```clojure
(enable-debug)
Expand All @@ -460,10 +460,10 @@ Compute the result. The pre-defined lazy operations will be executed in pipeline
| Argument | Type | Function | Remarks |
| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `dataframe` | clojask.classes.DataFrame.DataFrame / clojask.classes.JoinedDataFrame.JoinedDataFrame | The operated object | |
| `num of workers` | int | The number of worker instances (except the input and output nodes) | Uses [Onyx](https://github.com/clojure-finance/onyx) as the distributed platform. Group-by and aggregate computes accept at most 8 workers. |
| `num of workers` | int | The number of worker threads (besides the thread that reads the input and the calling thread, which writes the output) | An integer from 1 to 8, for every kind of compute. |
| `output path` | String / `nil` | The path of the output csv file | If the path already exists, will overwrite the file.<br>If `nil`, will store the output in memory as a vector of vectors, which represent each row, with the header row first unless `:header false`. See [example](https://github.com/clojure-finance/clojask-examples/blob/main/src/clojask_examples/in_memory.clj). |
| [`exception`] | Boolean | Whether an exception during calculation will cause termination | By default `false`. Is useful for debugging or detecting empty fields |
| [`order`] | Boolean | If enforce the order of rows in the output to be the same as input | By default `false`. If set to `true`, will sacrifice the performance. |
| [`order`] | Boolean | Has no effect since 2.1 | Accepted so that existing calls keep working. Output rows are always in input order, except that group-by and outer joins write theirs in group order. |
| [`output`] | Function | Specify how to output a row vector to the output file | Takes two arguments.<br />`writer` java.io.BufferedWriter<br />`rows` clojure.lang.PersistentVector (rows) of clojure.lang.PersistentVector (each row) |
| [`select`] | String / Collection of strings | Chooses columns to select for the operation | Can only specify either of select and exclude |
| [`exclude`] | String / Collection of strings | Chooses columns to be excluded for the operation | Can only specify either of select and exclude |
Expand All @@ -484,9 +484,6 @@ A `clojask.classes.DataFrame.DataFrame` read from the output file (read without
(compute x 8 "output.csv" :select "col a")
;; only select column a

(compute x 8 "output.csv" :order true)
;; make sure the order of the output is the same of the input

(compute x 8 nil :in-memory true)
;; compute the dataframe in memory and store the dataframe also in memory

Expand Down
18 changes: 5 additions & 13 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
(defproject com.github.clojure-finance/clojask "2.0.6"
(defproject com.github.clojure-finance/clojask "2.1.0"
:description "Data analysis and manipulation library with parallel computing for larger-than-memory datasets"
:url "https://github.com/clojure-finance/clojask"
:license {:name "MIT"
:url "https://github.com/clojure-finance/clojask/blob/1.x.x/LICENSE"}
:dependencies [[org.clojure/clojure "1.11.1"]
:dependencies [[org.clojure/clojure "1.12.6"]
;; [org.clojure/math.numeric-tower "0.0.4"]
[org.clojure/data.csv "1.0.0"]
[com.github.clojure-finance/onyx "0.16.0"]
[com.taoensso/timbre "5.2.1"]
;; [techascent/tech.ml.dataset "5.17" :exclusions [[ch.qos.logback/logback-classic][org.slf4j/slf4j-api]]]
[com.google.code.externalsortinginjava/externalsortinginjava "0.6.0"]
[com.github.clojure-finance/clojask-io "1.0.8"]
[com.github.clojure-finance/clojure-heap "1.0.3"]]
[com.google.code.externalsortinginjava/externalsortinginjava "0.6.6"]
[com.github.clojure-finance/clojask-io "1.0.8"]]
;; lein deploy clojars, credentials from CLOJARS_USERNAME / CLOJARS_PASSWORD
:deploy-repositories [["clojars" {:url "https://clojars.org/repo"
:username :env/clojars_username
Expand All @@ -21,11 +17,7 @@
:source-paths ["src/main/clojure"]
:java-source-paths ["src/main/java"]
:javac-options ["--release" "17"]
;; Onyx's Aeron messaging (via Agrona) reads jdk.internal.misc.Unsafe.
;; lz4 (via Onyx's nippy serialization) calls System.load; JDK 24+ warns without
;; native access enabled.
:jvm-opts ["-XX:+UseG1GC" "-server" "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED"
"--enable-native-access=ALL-UNNAMED"]
:jvm-opts ["-XX:+UseG1GC" "-server"]
:test-paths ["test/clojask"]
;:java-test-paths ["test/java"]
;;:injections [(.. System (setProperty "clojure.core.async.pool-size" "8"))]
Expand Down
89 changes: 0 additions & 89 deletions src/main/clojure/clojask/aggregate/aggre_input.clj

This file was deleted.

Loading
Loading