Menu

Get Started

Introduction

This guide contains simple steps showing how to transact data and run a simple query. However, there are a few topics you might benefit from learning about before you get too far with attempting to use Crux:

  • EDN – the extensible data notation format used throughout the Crux APIs, see Essential EDN for Crux.

  • The Datalog query language – Crux supports an EDN-flavoured version of Datalog. The Queries section within this documentation provides a good overview. You can also find an interactive tutorial for EDN-flavoured Datalog here.

  • Clojure – whilst a complete Java and HTTP API is provided, a basic understanding of Clojure is recommended – Clojure is a succinct and pragmatic data-oriented language with strong support for immutability and parallelism. See Clojure.org.

Setting Up

Follow the below steps to quickly set yourself up a Crux playground…​

Project Dependency

First add the crux-core module as a project dependency:

  juxt/crux-core {:mvn/version "20.09-1.11.0-beta"}

Start a Crux node

(require '[crux.api :as crux]
         '[clojure.java.io :as io])

(defn start-standalone-node ^crux.api.ICruxAPI [storage-dir]
  (crux/start-node {:crux.node/topology '[crux.standalone/topology]
                    :crux.standalone/event-log-dir (io/file storage-dir "event-log")
                    :crux.kv/db-dir (io/file storage-dir "indexes")}))

(comment ; which can be used as
  (def node (start-standalone-node "crux-store")))

For the purposes of this "Hello World" we are using the simplest configuration of Crux, which only requires the crux-core module. All of the logs and indexes are held purely in-memory, so your data won’t be persisted across restarts. This is useful when testing and experimenting as there is no additional complexity or stateful use of Kafka or RocksDB to think about.

Once started, the node gives us access to an empty Crux database instance and API for running transactions and issuing queries. Depending on how you configure your topology, multiple nodes may share the same database, but in this case your node exclusively owns the database instance. If a Kafka or JDBC module topology was used instead then the same database instance would be available across multiple nodes to provide fault-tolerant durability, high-availabilty and horizontal scaling.

Transacting

(crux/submit-tx
 node
 [[:crux.tx/put
   {:crux.db/id :dbpedia.resource/Pablo-Picasso ; id
    :name "Pablo"
    :last-name "Picasso"}
   #inst "2018-05-18T09:20:27.966-00:00"]]) ; valid time

Querying

A query executes against a db context. This db context represents the database "as a value" at a fixed & consistent point-in-time against which other APIs can be used. The db context should be thought of as a lightweight reference - it is not a container for a resource or lock. The point-in-time is implicitly "now", unless otherwise specified, and there the context returned represents the latest view of the database following the most recently processed transaction. The main query API is eager but you may also consume the results lazily as the entire Crux query engine and index structure is lazy by design.

(crux/q (crux/db node)
        '{:find [e]
          :where [[e :name "Pablo"]]})

You should get:

#{[:dbpedia.resource/Pablo-Picasso]}

An entity query would be:

(crux/entity (crux/db node) :dbpedia.resource/Pablo-Picasso)

You should get:

{:crux.db/id :dbpedia.resource/Pablo-Picasso
 :name "Pablo"
 :last-name "Picasso"}

Next Steps

Now you know the basics of how to interact with Crux you may want to dive into our tutorials. Otherwise, let’s take a look at further options for setting up Crux.