# luan:lucene/Lucene.luan
Lucene is the database for Luan's dynamic sites. A document is a flat table of fields.
- `Lucene.index(dir, options)`: opens or creates an index in the `file:` URI `dir`, and returns a table of functions (below). Options used so far:
- `default_type`: the field type for fields not listed in `indexed_fields`, such as `Lucene.type.english`, which stems words so "search" finds "searches".
- `default_fields`: a list of fields searched by query words that have no field prefix.
- `log_dir`: a `file:` URI. Every change is also written to this log. See `restore_from_log` and `check`.
- `name`: registers the index for the backup RPC functions.
- `Lucene.type`: field types: `english`, `string`, `lowercase`, `simple`, `standard`, `integer`, `long`, `double`, `float`.
- `index.save(doc)`: a doc with no `id` gets the next id (a Java long, starting at 1 for a new index), and `doc.id` is set. A doc with an `id` replaces the stored doc with that id. Ids aren't reused after a delete.
- `index.search(query, from, to, {sort=...})`: returns a list of docs (hits `from` to `to`, starting at 1) and the total number of hits. Sort is like `"id desc"`. Numbers come back as numbers.
- `index.get_document(query)`: the one matching doc, or nil. Errors if more than one matches.
- `index.count(query)`: the number of matching docs.
- `index.delete(query)`: deletes every matching doc.
- `index.run_in_transaction(fn)`: takes the index's write lock, runs `fn`, commits, and returns what `fn` returns. If `fn` raises an error, every change since the transaction began is rolled back. A nested call joins the outer transaction, so an error inside it rolls back the outer one too.
- `index.not_in_transaction()`: called by `index.save` when it runs outside a transaction (`index.delete` doesn't call it). It does nothing by default. Sites define it to log an error, so a save that forgot its transaction shows up in the log.
- Queries use goodjava's query parser, which has Lucene's syntax: `type:post`, `+type:post +id:5` (both required), plain words for `default_fields`.
- Every index can hold different kinds of doc, kept apart by a `type` field by convention. So a lookup by id alone can return the wrong kind. `index.update` itself saves a `type:version` doc, so it takes id 1 in a new index. Check the type of what a lookup returns.
- `index.update{ [1]=fn1, [2]=fn2, ... }`: database migrations. Runs each step newer than the version stored in the `type:version` doc, in a transaction, then saves the new version. Each step is logged at error level on purpose, so migrations stand out in the log.
- `index.restore_from_log()`: if the index directory was just created but the log already existed, rebuilds the index from the log. Call it at startup.
- `index.check()`: checks the index and checks that the log matches it. Sites schedule it hourly with `Thread.schedule`.
- `index.zip(file)`: writes a zip of a snapshot of the index, using the `zip` command.