# Core concepts

Source: https://docs.littlebigbrain.com/start/concepts/

If you have used a vector store, you know half of this model already. This
page maps what you know to little big brain. Then it explains the two new
parts: links between records, and commits.

To run something first, start with the [quickstart](https://docs.littlebigbrain.com/start/quickstart/). This
page uses its example: support tickets, bugs and releases.

## From a vector store

| In a vector store | In little big brain |
| --- | --- |
| Index or collection | Graph |
| Document or chunk | Record |
| Metadata fields | Fields, with declared types |
| No equivalent | Links between records |
| Embeddings you compute and upsert | Embeddings the platform computes from the fields you choose |
| Metadata filter | Filter by type and by link |
| An upsert overwrites the old value | Each write is a new commit, and past commits stay readable |

The main difference is the links. A vector store finds chunks that are similar
to a question. It cannot tell you how two facts connect. Here, links are stored
data. A query can follow them, and an answer can show them.

## Stacks and graphs

A **stack** is an isolated workspace. It has its own endpoint, API keys and
data. Use one stack per environment, such as `production` and `staging`.

A **graph** is one dataset in a stack, such as `support`. Calls name it with
`?graph=`, or with the `graph` option of an SDK client. The default is `main`.

Internally, each stack is served as its own **tenant**. You see it only as the
short id at the start of your endpoint's host.

## Records, types, links and fields

| Term | In the API and RDF | What it is | Example |
| --- | --- | --- | --- |
| Record | Entity | One thing in your data | ticket 4821 |
| Type | Class | A kind of record | `Ticket` |
| Link | Relation | A named connection from one record to another | `REPORTED_AS`, from a ticket to a bug |
| Field | Property | A typed value on a record | `description` |

A record has a `type`, a `name` and usually a `key`. The key is the id from
your source system. Two records with the same type and key are one record. A
rename keeps the record. In a write, records look like this:

```json
{
  "source": { "type": "Ticket", "key": "4821", "name": "login fails after 3.1" },
  "relation": "REPORTED_AS",
  "target": { "type": "Bug", "key": "AUTH-112", "name": "session token expiry" },
  "evidence": "Support triage, 2 Sep"
}
```

A link can carry `evidence`, a note on why the fact was recorded. Put a source
reference there, such as a document id or a URL. An agent can then cite it.
Evidence can also name a `source_id` and a page `region`. Reads return it:
`GET /v1/graph/entity` lists each link's evidence, and SPARQL reads it from
the link's statement node. A document workflow names a file as the source:
its `Document` IRI with the page, as in `…/e/41ab…#page=3`.

A link can also carry `properties`: values of fields in your schema, such as
a status. `GET /v1/graph/entity` returns them on each link. SPARQL reads them
under `https://littlebigbrain.com/ep/`.

## Schema

A graph accepts only the types, links and fields you declare. `define`
declares types and links. `evolve` adds fields and more types later.

A write can name an unknown type or field. It can give a value of the wrong
type. Then the whole write fails, and nothing from it is stored.
[Load your data](https://docs.littlebigbrain.com/start/load-data/) shows the order of steps.

For rules across fields and links, publish **SHACL shapes**. An example rule is
"a released batch names the lot it was produced from".

In reject mode, the platform refuses a write that breaks a rule. The error
reports what to fix. An agent can read the report, correct its write and
retry. See [Query and validate](https://docs.littlebigbrain.com/guides/sparql-and-shacl/).

## Commits

Each write is a **commit** with a number, `commit_seq`. The numbers only go up.
Each read reports the commit it answered from, as `served_at_seq`.

Writes do not overwrite data in place. A new value is a new commit, and past
commits stay readable. Pass `as_of_commit_seq` to run a query against the graph
as it was at that commit. This works while the commit is retained. See
[Replay an answer](https://docs.littlebigbrain.com/guides/time-travel-audit/).

A commit over HTTP needs an `Idempotency-Key` header. The SDKs create one when
you do not pass it.

A request with a key that was used before returns the first
result with `replayed: true`. It writes nothing new, even when the payload
changed. Use a new key for new data.

## When a read sees your write

After a commit, the platform publishes it for queries and search. This usually
takes a second or two. Reads take a `consistency` option:

- `eventual` is the default. It reads the latest published commit. It is fast,
  and it can be a little behind the newest write.
- `strong` also applies the newest writes. Use it to read your own write at
  once.

To wait for one write, pass its `commit_seq` as `min_indexed_seq`. The read
then covers that commit or a later one.

Search follows published commits. Each embedding reports `lag_commits`, the
number of commits it is behind the newest commit. It catches up after each
publication. To search your own write, pass its `commit_seq` as
`min_commit_seq`.

## Search by meaning

You declare an **embedding** on a type and choose the fields to embed. The
platform builds one text per record from those fields and embeds it. It keeps
the vectors current as records change. One graph uses one embedding model.

A search embeds your question and finds the nearest records. Then it checks
each hit against the graph at one commit. A deleted record does not come back.

You can filter by type and by link, such as "services that call
payment-service". See [Search by meaning](https://docs.littlebigbrain.com/guides/search-by-meaning/).

## Graph queries with SPARQL

Search finds starting points. A graph query follows the links from them. The
query language is **SPARQL 1.1**, the W3C standard for graph queries.

A SPARQL query is made of patterns. Each pattern is a record, a link, then a
record or a value. Names that start with `?` are variables.

The query returns the values that fit all patterns at once. This query lists
each ticket with the release that fixed it:

```sparql
PREFIX dclass: <https://littlebigbrain.com/class/>
PREFIX dr: <https://littlebigbrain.com/r/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?ticket ?release WHERE {
  ?t a dclass:ticket ; rdfs:label ?ticket ; dr:reported_as ?b .
  OPTIONAL { ?b dr:fixed_in ?r . ?r rdfs:label ?release . }
}
ORDER BY ?ticket
```

`a` means "has type". A `;` starts the next pattern about the same record.
`OPTIONAL` keeps a ticket whose bug has no fix yet.

The names you declare in JSON have fixed global names in queries:

| You declared | In SPARQL | Prefix line |
| --- | --- | --- |
| Type `Ticket` | `dclass:ticket` | `PREFIX dclass: <https://littlebigbrain.com/class/>` |
| Link `REPORTED_AS` | `dr:reported_as` | `PREFIX dr: <https://littlebigbrain.com/r/>` |
| Field `description` | `dp:description` | `PREFIX dp: <https://littlebigbrain.com/p/>` |
| A record's `name` | `rdfs:label` | `PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>` |

The global names use lowercase. If you know Cypher, this table maps the common
patterns:

| Cypher | SPARQL |
| --- | --- |
| `MATCH (t:Ticket)` | `?t a dclass:ticket .` |
| `(t)-[:REPORTED_AS]->(b)` | `?t dr:reported_as ?b .` |
| `(a)-[:DEPENDS_ON*1..]->(b)` | `?a dr:depends_on+ ?b .` |
| `t.description` | `?t dp:description ?d .` |
| `WHERE NOT (e)-[:APPROVED_BY]->()` | `FILTER NOT EXISTS { ?e dr:approved_by ?x }` |
| `RETURN t.name` | `SELECT ?name` with `?t rdfs:label ?name .` |

[Query and validate](https://docs.littlebigbrain.com/guides/sparql-and-shacl/) covers filters, aggregates and
paths. [Use cases](https://docs.littlebigbrain.com/start/use-cases/) shows six complete queries.

## RDF under the hood

You do not need RDF to use little big brain. The words appear in responses and
queries, so they help.

Each fact is stored as a **triple**: a subject, a predicate and an object.
"ticket 4821, `REPORTED_AS`, bug AUTH-112" is one triple. "ticket 4821, name,
'login fails after 3.1'" is another.

A graph is a set of triples. This data model is **RDF**, a W3C standard.

| Word | Meaning |
| --- | --- |
| IRI | A global name for a record, type or link. It looks like a URL, such as `https://littlebigbrain.com/class/ticket`. Records you write as JSON get IRIs such as `https://littlebigbrain.com/e/0ea0bc08…`. |
| Literal | A plain value, such as a string, a number or a date. |
| Class | A type. |
| Ontology | The declared types, links and fields of a graph. |
| SHACL | The W3C standard for validation rules. |
| RDFS and OWL | W3C standards that say how types and links relate, such as "an active study site is a study site". |
| Turtle, N-Triples | Text formats for RDF data. |

RDF is the reason standard tools work here. You query with SPARQL, validate
with SHACL, and connect tools such as YASGUI, Protégé or RDFLib. If your data
is RDF already, [load it as it is](https://docs.littlebigbrain.com/guides/load-rdf/).

## Reasoning

A query can also return facts that follow from your schema. Say the schema
states that an active study site is a study site. A query for study sites can
then include the active ones.

You choose this per query with the `entailment` option. The default, `none`,
returns the facts as written. See [Reasoning & inference](https://docs.littlebigbrain.com/guides/reasoning/).

## Where your data lives

Your graph lives in object storage. Facts, indexes, vectors and history are
immutable objects in one bucket.

The servers in front cache hot data on local NVMe disks and keep no durable
state. A server can restart or be replaced at any time. You pay for the bytes
you store. See [Usage & billing](https://docs.littlebigbrain.com/start/billing/).
