/** @file
* @brief An indexed database of documents
*/
/* Copyright 2003-2026 Olly Betts
* Copyright 2007,2008,2009 Lemur Consulting Ltd
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see
* .
*/
#ifndef XAPIAN_INCLUDED_DATABASE_H
#define XAPIAN_INCLUDED_DATABASE_H
#if !defined XAPIAN_IN_XAPIAN_H && !defined XAPIAN_LIB_BUILD
# error Never use directly; include instead.
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace Xapian {
class Compactor;
class Document;
class WritableDatabase;
/** An indexed database of documents.
*
* A Database object contains zero or more shards, and operations are
* performed across these shards.
*
* To perform a search on a Database, you need to use an Enquire object.
*
* @since 2.0.0 This class is a reference counted handle like many other
* Xapian API classes. In earlier versions, it worked like a typedef
* to std::vector. The key difference is that
* previously copying or assigning a Xapian::Database made a deep copy,
* whereas now it makes a shallow copy.
*
* Most methods can throw:
*
* @exception Xapian::DatabaseCorruptError if database corruption is detected
* @exception Xapian::DatabaseError in various situation (for example, if
* there's an I/O error).
* @exception Xapian::DatabaseModifiedError if the revision being read has
* been discarded
* @exception Xapian::DatabaseClosedError may be thrown by some methods after
* after @a close() has been called
* @exception Xapian::NetworkError when remote databases are in use
*/
class XAPIAN_VISIBILITY_DEFAULT Database {
/// @internal Implementation behind check() static methods.
static size_t check_(const std::string_view* path_ptr,
int fd,
int opts,
std::ostream* out);
/// @internal Implementation behind public compact() methods.
void compact_(const std::string_view* output_ptr,
int fd,
unsigned flags,
int block_size,
Xapian::Compactor* compactor) const;
protected:
/// @private @internal Implementation behind public add_database() methods.
void add_database_(const Database& other, bool read_only);
public:
/// Class representing the Database internals.
class Internal;
/// @private @internal Reference counted internals.
Xapian::Internal::intrusive_ptr_nonnull internal;
/** Add shards from another Database.
*
* Any shards in @a other are appended to the list of shards in this
* object. The shards are reference counted and also remain in @a other.
*
* @param other Another Database to add shards from
*
* @exception Xapian::InvalidArgumentError if @a other is the same object
* as this.
*/
void add_database(const Database& other) {
add_database_(other, true);
}
/** Return number of shards in this Database object.
*
* If you want the number of documents, see @ get_doccount().
*
* @since Xapian 1.4.12
*/
size_t size() const;
/** Construct a Database containing no shards.
*
* You can then add shards by calling add_database(). A Database
* containing no shards can also be useful in situations where you need an
* empty database.
*/
Database();
/** Open a Database.
*
* @param path Filing system path to open database from
* @param flags Bitwise-or of Xapian::DB_* constants
*
* The @a path can be a file (for a stub database or a single-file glass
* database) or a directory (for a standard glass database). If
* @a flags includes @a DB_BACKEND_INMEMORY then @a path is ignored.
*
* @exception Xapian::DatabaseOpeningError if the specified database
* cannot be opened
* @exception Xapian::DatabaseVersionError if the specified database has
* a format too old or too new to be supported.
*/
explicit Database(std::string_view path, int flags = 0);
/** Open a single-file Database.
*
* This method opens a single-file Database given a file descriptor open
* on it. Xapian looks starting at the current file offset, allowing a
* single file database to be easily embedded within another file.
*
* @param fd File descriptor for the file. Xapian takes ownership
* of this and will close it when the database is closed.
* @param flags Bitwise-or of Xapian::DB_* constants.
*
* @exception Xapian::DatabaseOpeningError if the specified database
* cannot be opened
* @exception Xapian::DatabaseVersionError if the specified database has
* a format too old or too new to be supported.
*/
explicit Database(int fd, int flags = 0);
/// @private @internal Wrap an existing Internal.
XAPIAN_VISIBILITY_INTERNAL
explicit Database(Internal* internal) XAPIAN_NONNULL();
/// Destructor.
virtual ~Database();
/** Copy constructor.
*
* The internals are reference counted, so copying is cheap.
*/
Database(const Database& o);
/** Assignment operator.
*
* The internals are reference counted, so assignment is cheap.
*/
Database& operator=(const Database& o);
/// Move constructor.
Database(Database&& o);
/// Move assignment operator.
Database& operator=(Database&& o);
/** Reopen the database at the latest available revision.
*
* Xapian databases (at least with most backends) support versioning
* such that a Database object uses a snapshot of the database.
* However, write operations may cause this snapshot to be discarded,
* which can cause Xapian::DatabaseModifiedError to be thrown. You
* can recover from this situation by calling reopen() and restarting
* the search operation.
*
* All shards are updated to the latest available revision. This should
* be a cheap operation if they're already at the latest revision, so
* if you're using the same Database object for many searches it's
* reasonable to call reopen() before each search.
*
* @return true if one or more shards have moved to a newer revision
* (if false is returned then it's definitely the case that no
* shards were reopened, which applications may find useful when
* caching results, etc). In Xapian < 1.3.0, this method did not
* return a value.
*
* @exception Xapian::DatabaseError is thrown if close() has been called
* on any of the shards.
*/
bool reopen();
/** Close the database.
*
* This closes the database and closes all its file handles.
*
* For a WritableDatabase, if a transaction is active it will be aborted,
* while if no transaction is active commit() will be implicitly called.
* Also the write lock is released.
*
* Calling close() on an object cannot be undone - in particular, a
* subsequent call to reopen() on the same object will not reopen it, but
* will instead throw a Xapian::DatabaseClosedError exception.
*
* Calling close() again on an object which has already been closed has
* no effect (and doesn't raise an exception).
*
* After close() has been called, calls to other methods of the database,
* and to methods of other objects associated with the database, will
* either:
*
* - behave exactly as they would have done if the database had not been
* closed (this can only happen if all the required data is cached)
*
* - raise a Xapian::DatabaseClosedError exception.
*
* The reason for this behaviour is that otherwise we'd have to check that
* the database is still open on every method call on every object
* associated with a Database, when in many cases they are working on data
* which has already been loaded and so they are able to just behave
* correctly.
*
* @since This method was added in Xapian 1.1.0.
*/
void close();
/// Return a string describing this object.
virtual std::string get_description() const;
/** Start iterating the postings of a term.
*
* @param term The term to iterate the postings of. An empty string
* acts as a special pseudo-term which indexes all the
* documents in the database with a wdf of 1.
*/
PostingIterator postlist_begin(std::string_view term) const;
/** End iterator corresponding to postlist_begin(). */
PostingIterator postlist_end(std::string_view) const noexcept {
return PostingIterator();
}
/** Start iterating the terms in a document.
*
* @param did The document id to iterate terms from
*
* The terms are returned in ascending string order (by byte value).
*/
TermIterator termlist_begin(Xapian::docid did) const;
/** End iterator corresponding to termlist_begin(). */
TermIterator termlist_end(Xapian::docid) const noexcept {
return TermIterator();
}
/** Does this database have any positional information? */
bool has_positions() const;
/** Start iterating positions for a term in a document.
*
* @param did The document id of the document
* @param term The term
*
* @since 1.1.0 If the specified document doesn't exist or the
* specified term doesn't exist in the specified document,
* then a valid iterator is still returned, but it will be
* equal to positionlist_end().
*/
PositionIterator positionlist_begin(Xapian::docid did,
std::string_view term) const;
/** End iterator corresponding to positionlist_begin(). */
PositionIterator positionlist_end(Xapian::docid,
std::string_view) const noexcept {
return PositionIterator();
}
/** Start iterating all terms in the database with a given prefix.
*
* The terms are returned in ascending string order (by byte value).
*
* @param prefix The prefix to restrict the returned terms to (default:
* iterate all terms)
*/
TermIterator allterms_begin(std::string_view prefix = {}) const;
/** End iterator corresponding to allterms_begin(prefix). */
TermIterator allterms_end(std::string_view = {}) const noexcept
{
return TermIterator();
}
/// Get the number of documents in the database.
Xapian::doccount get_doccount() const;
/// Get the highest document id which has been used in the database.
Xapian::docid get_lastdocid() const;
/// Get the mean document length in the database.
double get_average_length() const;
/// Old name for get_average_length() for backward compatibility.
double get_avlength() const { return get_average_length(); }
/** Get the total length of all the documents in the database.
*
* @since Added in Xapian 1.4.5.
*/
Xapian::totallength get_total_length() const;
/** Get the number of documents indexed by a specified term.
*
* @param term The term to get the frequency of. An empty string
* acts as a special pseudo-term which indexes all the
* documents in the database, so returns get_doccount().
* If the term isn't present in the database, 0 is
* returned.
*/
Xapian::doccount get_termfreq(std::string_view term) const;
/** Test is a particular term is present in any document.
*
* @param term The term to test for. An empty string acts as a
* special pseudo-term which indexes all the documents in
* the database, so returns true if the database contains
* any documents.
*
* db.term_exists(t) gives the same answer as db.get_termfreq(t) != 0, but
* is typically more efficient.
*/
bool term_exists(std::string_view term) const;
/** Get the total number of occurrences of a specified term.
*
* The collection frequency of a term is defined as the total number of
* times it occurs in the database, which is the sum of its wdf in all the
* documents it indexes.
*
* @param term The term to get the collection frequency of. An empty
* string acts as a special pseudo-term which indexes all
* the documents in the database, so returns
* get_doccount(). If the term isn't present in the
* database, 0 is returned.
*/
Xapian::termcount get_collection_freq(std::string_view term) const;
/** Return the frequency of a given value slot.
*
* This is the number of documents which have a (non-empty) value stored
* in the slot.
*
* @param slot The value slot to examine.
*/
Xapian::doccount get_value_freq(Xapian::valueno slot) const;
/** Get a lower bound on the values stored in the given value slot.
*
* If there are no values stored in the given value slot, this will return
* an empty string.
*
* @param slot The value slot to examine.
*/
std::string get_value_lower_bound(Xapian::valueno slot) const;
/** Get an upper bound on the values stored in the given value slot.
*
* If there are no values stored in the given value slot, this will return
* an empty string.
*
* @param slot The value slot to examine.
*/
std::string get_value_upper_bound(Xapian::valueno slot) const;
/** Get a lower bound on the length of a document in this DB.
*
* This bound does not include any zero-length documents.
*/
Xapian::termcount get_doclength_lower_bound() const;
/// Get an upper bound on the length of a document in this DB.
Xapian::termcount get_doclength_upper_bound() const;
/// Get an upper bound on the wdf of term @a term.
Xapian::termcount get_wdf_upper_bound(std::string_view term) const;
/** Get a lower bound on the unique terms size of a document in this DB.
*
* @since Added in Xapian 2.0.0.
*/
Xapian::termcount get_unique_terms_lower_bound() const;
/** Get an upper bound on the unique terms size of a document in this DB.
*
* @since Added in Xapian 2.0.0.
*/
Xapian::termcount get_unique_terms_upper_bound() const;
/// Return an iterator over the value in slot @a slot for each document.
ValueIterator valuestream_begin(Xapian::valueno slot) const;
/// Return end iterator corresponding to valuestream_begin().
ValueIterator valuestream_end(Xapian::valueno) const noexcept {
return ValueIterator();
}
/** Get the length of a specified document.
*
* @param did The document id of the document
*
* Xapian defines a document's length as the sum of the wdf of all the
* terms which index it.
*/
Xapian::termcount get_doclength(Xapian::docid did) const;
/** Get the number of unique terms in a specified document.
*
* @param did The document id of the document
*
* This is the number of different terms which index the given document.
*/
Xapian::termcount get_unique_terms(Xapian::docid did) const;
/** Get the maximum wdf value in a specified document.
*
* @param did The document id of the document
*
* @since Added in Xapian 2.0.0.
*/
Xapian::termcount get_wdfdocmax(Xapian::docid did) const;
/** Send a keep-alive message.
*
* For remote databases, this method sends a message to the server to
* reset the timeout timer. As well as preventing timeouts at the Xapian
* remote protocol level, this message will also avoid timeouts at lower
* levels.
*
* For local databases, this method does nothing.
*/
void keep_alive();
/** Get a document from the database.
*
* The returned object acts as a handle which lazily fetches information
* about the specified document from the database.
*
* @param did The document ID of the document to be get
* @param flags Zero or more flags bitwise-or-ed together (currently
* only Xapian::DOC_ASSUME_VALID is supported).
* (default: 0)
*
* @since The @a flags parameter was added in Xapian 2.0.0.
*
* @exception Xapian::InvalidArgumentError is thrown if @a did is 0.
*
* @exception Xapian::DocNotFoundError is thrown if the specified docid
* is not present in this database.
*/
Xapian::Document get_document(Xapian::docid did,
unsigned flags = 0) const;
/** Suggest a spelling correction.
*
* @param word The potentially misspelled word.
* @param max_edit_distance Only consider words which are at most
* @a max_edit_distance edits from @a word.
* An edit is a character insertion, deletion,
* or the transposition of two adjacent
* characters (default is 2).
*/
std::string get_spelling_suggestion(std::string_view word,
unsigned max_edit_distance = 2) const;
/** An iterator which returns all the spelling correction targets.
*
* This returns all the words which are considered as targets for the
* spelling correction algorithm. The frequency of each word is available
* as the term frequency of each entry in the returned iterator.
*/
Xapian::TermIterator spellings_begin() const;
/// End iterator corresponding to spellings_begin().
Xapian::TermIterator spellings_end() const noexcept {
return Xapian::TermIterator();
}
/** An iterator which returns all the synonyms for a given term.
*
* @param term The term to return synonyms for.
*/
Xapian::TermIterator synonyms_begin(std::string_view term) const;
/// End iterator corresponding to synonyms_begin(term).
Xapian::TermIterator synonyms_end(std::string_view) const noexcept {
return Xapian::TermIterator();
}
/** An iterator which returns all terms which have synonyms.
*
* @param prefix If non-empty, only terms with this prefix are returned.
*/
Xapian::TermIterator synonym_keys_begin(std::string_view prefix = {}) const;
/// End iterator corresponding to synonym_keys_begin(prefix).
Xapian::TermIterator
synonym_keys_end(std::string_view = {}) const noexcept {
return Xapian::TermIterator();
}
/** Get the user-specified metadata associated with a given key.
*
* User-specified metadata allows you to store arbitrary information in
* the form of (key, value) pairs. See @a
* WritableDatabase::set_metadata() for more information.
*
* When invoked on a Xapian::Database object representing multiple
* databases, currently only the metadata for the first is considered but
* this behaviour may change in the future.
*
* If there is no piece of metadata associated with the specified key, an
* empty string is returned (this applies even for backends which don't
* support metadata).
*
* Empty keys are not valid, and specifying one will cause an exception.
*
* @param key The key of the metadata item to access.
*
* @return The retrieved metadata item's value.
*
* @exception Xapian::InvalidArgumentError will be thrown if the key
* supplied is empty.
*/
std::string get_metadata(std::string_view key) const;
/** An iterator which returns all user-specified metadata keys.
*
* When invoked on a Xapian::Database object representing multiple
* databases, currently only the metadata for the first is considered but
* this behaviour may change in the future.
*
* If the backend doesn't support metadata, then this method returns an
* iterator which compares equal to that returned by metadata_keys_end().
*
* @param prefix If non-empty, only keys with this prefix are returned.
*
* @exception Xapian::UnimplementedError will be thrown if the backend
* implements user-specified metadata, but doesn't implement
* iterating its keys (currently this happens for the InMemory
* backend).
*/
Xapian::TermIterator
metadata_keys_begin(std::string_view prefix = {}) const;
/// End iterator corresponding to metadata_keys_begin().
Xapian::TermIterator
metadata_keys_end(std::string_view = {}) const noexcept {
return Xapian::TermIterator();
}
/** Get the UUID for the database.
*
* The UUID will persist for the lifetime of the database.
*
* Replicas (eg, made with the replication protocol, or by copying all the
* database files) will have the same UUID. However, copies (made with
* copydatabase, or xapian-compact) will have different UUIDs.
*
* If the backend does not support UUIDs or this database has no
* subdatabases, the UUID will be empty.
*
* If this database has multiple sub-databases, the UUID string will
* contain the UUIDs of all the sub-databases separated by colons.
*/
std::string get_uuid() const;
/** Test if this database is currently locked for writing.
*
* If the underlying object is actually a WritableDatabase, always returns
* true unless close() has been called.
*
* Otherwise tests if there's a writer holding the lock (or if we can't
* test for a lock without taking it on the current platform, throw
* Xapian::UnimplementedError). If there's an error while trying to test
* the lock, throws Xapian::DatabaseLockError.
*
* For multi-databases, this tests each sub-database and returns true if
* any of them are locked.
*/
bool locked() const;
/** Lock a read-only database for writing.
*
* If the database is actually already writable (i.e. a WritableDatabase
* via a Database reference) then the same database is returned (with
* its flags updated, so this provides an efficient way to modify flags
* on an open WritableDatabase).
*
* Unlike unlock(), the object this is called on remains open.
*
* @param flags The flags to use for the writable database. Flags which
* specify how to open the database are ignored (e.g.
* DB_CREATE_OR_OVERWRITE doesn't result in the database
* being wiped), and flags which specify the backend are
* also ignored as they are only relevant when creating
* a new database.
*
* @return A WritableDatabase object open on the same database.
*
* @since Added in Xapian 2.0.0.
*/
Xapian::WritableDatabase lock(int flags = 0);
/** Release a database write lock.
*
* If called on a read-only database then the same database is returned.
*
* If called on a writable database, the object this method was called
* on is closed.
*
* @return A Database object open on the same database.
*
* @since Added in Xapian 2.0.0.
*/
Xapian::Database unlock();
/** Get the revision of the database.
*
* The revision is an unsigned integer which increases with each commit.
* In practice it typically increments by one for each revision but you
* should not rely on that.
*
* @since Xapian 1.4.13 and later return 0 for a database consisting of no
* shards.
*
* @exception Xapian::InvalidOperationError If the database consists of
* more than one shard. In Xapian < 1.4.13, this is also thrown
* if the database consists of no shards.
* @exception Xapian::UnimplementedError Currently this is only
* implemented for glass (and for chert in Xapian 1.4.x).
*/
Xapian::rev get_revision() const;
/** Check the integrity of a database or database table.
*
* @param path Path to database or table
* @param opts Options to use for check
* @param out std::ostream to write output to (NULL for no output)
*/
static size_t check(std::string_view path,
int opts = 0,
std::ostream* out = NULL) {
return check_(&path, 0, opts, out);
}
/** Check the integrity of a single file database.
*
* @param fd file descriptor for the database. The current file
* offset is used, allowing checking a single file
* database which is embedded within another file. Xapian
* takes ownership of the file descriptor and will close
* it before returning.
* @param opts Options to use for check
* @param out std::ostream to write output to (NULL for no output)
*/
static size_t check(int fd, int opts = 0, std::ostream* out = NULL) {
return check_(NULL, fd, opts, out);
}
/** Produce a compact version of this database.
*
* @param output Path to write the compact version to. This can be the
* same as an input if that input is a stub database (in
* which case the database(s) listed in the stub will be
* compacted to a new database and then the stub will be
* atomically updated to point to this new database).
*
* @param flags Any of the following combined using bitwise-or (| in
* C++):
* - Xapian::DBCOMPACT_NO_RENUMBER By default the document ids will
* be renumbered the output - currently by applying the same
* offset to all the document ids in a particular source database.
* If this flag is specified, then this renumbering doesn't
* happen, but all the document ids must be unique over all source
* databases. Currently the ranges of document ids in each source
* must not overlap either, though this restriction may be removed
* in the future.
* - Xapian::DBCOMPACT_MULTIPASS
* If merging more than 3 databases, merge the postlists in
* multiple passes, which is generally faster but requires more
* disk space for temporary files.
* - Xapian::DBCOMPACT_SINGLE_FILE
* Produce a single-file database (only supported for glass
* currently).
* - At most one of:
* - Xapian::Compactor::STANDARD - Don't split items unnecessarily.
* - Xapian::Compactor::FULL - Split items whenever it saves space
* (the default).
* - Xapian::Compactor::FULLER - Allow oversize items to save more
* space (not recommended if you ever
* plan to update the compacted
* database). @since 1.4.31 Has the
* same effect as FULL.
*
* - At most one of the following to specify the output format (currently
* only glass to honey conversion is supported, and all shards of the
* input must have the same format):
* - Xapian::DB_BACKEND_HONEY
*
* @param block_size This specifies the block size (in bytes) for to
* use for the output. For glass, the block size
* must be a power of 2 between 2048 and 65536
* (inclusive), and the default (also used if an
* invalid value is passed) is 8192 bytes.
*
* @since 1.3.4 This method was added to replace various methods of the
* Compactor class.
*/
void compact(std::string_view output,
unsigned flags = 0,
int block_size = 0) {
compact_(&output, 0, flags, block_size, NULL);
}
/** Produce a compact version of this database.
*
* This variant writes a single-file database to the specified file
* descriptor. Only the glass backend supports such databases, so
* this form is only supported for this backend.
*
* @param fd File descriptor to write the compact version to. The
* descriptor needs to be readable and writable (open with
* O_RDWR) and seekable. The current file offset is used,
* allowing compacting to a single file database embedded
* within another file. Xapian takes ownership of the
* file descriptor and will close it before returning.
*
* @param flags Any of the following combined using bitwise-or (| in
* C++):
* - Xapian::DBCOMPACT_NO_RENUMBER By default the document ids will
* be renumbered the output - currently by applying the same
* offset to all the document ids in a particular source database.
* If this flag is specified, then this renumbering doesn't
* happen, but all the document ids must be unique over all source
* databases. Currently the ranges of document ids in each source
* must not overlap either, though this restriction may be removed
* in the future.
* - Xapian::DBCOMPACT_MULTIPASS
* If merging more than 3 databases, merge the postlists in
* multiple passes, which is generally faster but requires more
* disk space for temporary files.
* - Xapian::DBCOMPACT_SINGLE_FILE
* Produce a single-file database (only supported for glass
* currently).
* - At most one of:
* - Xapian::Compactor::STANDARD - Don't split items unnecessarily.
* - Xapian::Compactor::FULL - Split items whenever it saves space
* (the default).
* - Xapian::Compactor::FULLER - Allow oversize items to save more
* space (not recommended if you ever
* plan to update the compacted
* database). @since 1.4.31 Has the
* same effect as FULL.
*
* @param block_size This specifies the block size (in bytes) for to
* use for the output. For glass, the block size
* must be a power of 2 between 2048 and 65536
* (inclusive), and the default (also used if an
* invalid value is passed) is 8192 bytes.
*
* @since 1.3.4 This method was added to replace various methods of the
* Compactor class.
*/
void compact(int fd,
unsigned flags = 0,
int block_size = 0) {
compact_(NULL, fd, flags, block_size, NULL);
}
/** Produce a compact version of this database.
*
* The @a compactor functor allows handling progress output and
* specifying how user metadata is merged.
*
* @param output Path to write the compact version to.
* This can be the same as an input if that input is a
* stub database (in which case the database(s) listed
* in the stub will be compacted to a new database and
* then the stub will be atomically updated to point to
* this new database).
*
* @param flags Any of the following combined using bitwise-or (| in
* C++):
* - Xapian::DBCOMPACT_NO_RENUMBER By default the document ids will
* be renumbered the output - currently by applying the same
* offset to all the document ids in a particular source database.
* If this flag is specified, then this renumbering doesn't
* happen, but all the document ids must be unique over all source
* databases. Currently the ranges of document ids in each source
* must not overlap either, though this restriction may be removed
* in the future.
* - Xapian::DBCOMPACT_MULTIPASS
* If merging more than 3 databases, merge the postlists in
* multiple passes, which is generally faster but requires more
* disk space for temporary files.
* - Xapian::DBCOMPACT_SINGLE_FILE
* Produce a single-file database (only supported for glass
* currently).
* - At most one of:
* - Xapian::Compactor::STANDARD - Don't split items unnecessarily.
* - Xapian::Compactor::FULL - Split items whenever it saves space
* (the default).
* - Xapian::Compactor::FULLER - Allow oversize items to save more
* space (not recommended if you ever
* plan to update the compacted
* database). @since 1.4.31 Has the
* same effect as FULL.
*
* @param block_size This specifies the block size (in bytes) for to
* use for the output. For glass, the block size
* must be a power of 2 between 2048 and 65536
* (inclusive), and the default (also used if an
* invalid value is passed) is 8192 bytes.
*
* @param compactor Functor
*
* @since 1.3.4 This method was added to replace various methods of the
* Compactor class.
*/
void compact(std::string_view output,
unsigned flags,
int block_size,
Xapian::Compactor& compactor)
{
compact_(&output, 0, flags, block_size, &compactor);
}
/** Produce a compact version of this database.
*
* The @a compactor functor allows handling progress output and specifying
* how user metadata is merged.
*
* This variant writes a single-file database to the specified file
* descriptor. Only the glass backend supports such databases, so this
* form is only supported for this backend.
*
* @param fd File descriptor to write the compact version to. The
* descriptor needs to be readable and writable (open with
* O_RDWR) and seekable. The current file offset is used,
* allowing compacting to a single file database embedded
* within another file. Xapian takes ownership of the
* file descriptor and will close it before returning.
*
* @param flags Any of the following combined using bitwise-or (| in
* C++):
* - Xapian::DBCOMPACT_NO_RENUMBER By default the document ids will
* be renumbered the output - currently by applying the same
* offset to all the document ids in a particular source database.
* If this flag is specified, then this renumbering doesn't
* happen, but all the document ids must be unique over all source
* databases. Currently the ranges of document ids in each source
* must not overlap either, though this restriction may be removed
* in the future.
* - Xapian::DBCOMPACT_MULTIPASS
* If merging more than 3 databases, merge the postlists in
* multiple passes, which is generally faster but requires more
* disk space for temporary files.
* - Xapian::DBCOMPACT_SINGLE_FILE
* Produce a single-file database (only supported for glass
* currently).
* - At most one of:
* - Xapian::Compactor::STANDARD - Don't split items unnecessarily.
* - Xapian::Compactor::FULL - Split items whenever it saves space
* (the default).
* - Xapian::Compactor::FULLER - Allow oversize items to save more
* space (not recommended if you ever
* plan to update the compacted
* database). @since 1.4.31 Has the
* same effect as FULL.
*
* @param block_size This specifies the block size (in bytes) for to
* use for the output. For glass, the block size
* must be a power of 2 between 2048 and 65536
* (inclusive), and the default (also used if an
* invalid value is passed) is 8192 bytes.
*
* @param compactor Functor
*
* @since 1.3.4 This method was added to replace various methods of the
* Compactor class.
*/
void compact(int fd,
unsigned flags,
int block_size,
Xapian::Compactor& compactor)
{
compact_(NULL, fd, flags, block_size, &compactor);
}
/** Reconstruct document text.
*
* This uses term positional information to reconstruct the document text
* which was indexed. Reading the required positional information is
* potentially quite I/O intensive.
*
* The reconstructed text will be missing punctuation and most
* capitalisation.
*
* @param did The document id of the document to reconstruct
* @param length Number of bytes of text to aim for - note that
* slightly more may be returned (default: 0 meaning
* unlimited)
* @param prefix Term prefix to reconstruct (default: none)
* @param start_pos First position to reconstruct (default: 0)
* @param end_pos Last position to reconstruct (default: 0 meaning all)
*
* @since Added in Xapian 2.0.0.
*/
std::string reconstruct_text(Xapian::docid did,
size_t length = 0,
std::string_view prefix = {},
Xapian::termpos start_pos = 0,
Xapian::termpos end_pos = 0) const;
};
/** This class provides read/write access to a database.
*
* A WritableDatabase object contains zero or more shards, and operations are
* performed across these shards. Documents added by add_document() are
* stored to the shards in a round-robin fashion.
*
* @since 2.0.0 This class is a reference counted handle like many other
* Xapian API classes. In earlier versions, it worked like a typedef
* to std::vector. The key difference is that
* previously copying or assigning a Xapian::Database made a deep copy,
* whereas now it makes a shallow copy.
*
* Most methods can throw:
*
* @exception Xapian::DatabaseCorruptError if database corruption is detected
* @exception Xapian::DatabaseError in various situation (for example, calling
* methods after @a close() has been called)
* @exception Xapian::NetworkError when remote databases are in use
*/
class XAPIAN_VISIBILITY_DEFAULT WritableDatabase : public Database {
/** @internal @private Helper method which implements cancel_transaction()
* and commit_transaction().
*
* @param do_commit If true, then commit, else cancel.
*/
void end_transaction_(bool do_commit);
public:
/** Create a WritableDatabase with no subdatabases.
*
* The created object isn't very useful in this state - it's intended
* as a placeholder value.
*/
WritableDatabase() : Database() {}
/** Add shards from another WritableDatabase.
*
* Any shards in @a other are added to the list of shards in this object.
* The shards are reference counted and also remain in @a other.
*
* @param other Another WritableDatabase to add shards from
*
* @exception Xapian::InvalidArgumentError if @a other is the same object
* as this.
*/
void add_database(const WritableDatabase& other) {
// This method is provided mainly so that adding a Database to a
// WritableDatabase is a compile-time error - prior to 2.0.0, it
// would essentially act as a "black-hole" shard which discarded
// any changes made to it.
add_database_(other, false);
}
/** Create or open a Xapian database for both reading and writing.
*
* @param path Filing system path for the database. If creating a
* new database with a backend which uses a directory of
* files (such as glass does by default) then Xapian will
* create a directory for @a path if necessary (but the
* parent directory must already exist).
*
* @param flags A bitwise-or (| in C++) combination of:
*
* * at most one of the following constants indicating how to handle
* the database already existing or not (the default action is
* Xapian::DB_CREATE_OR_OPEN):
*
* Constant | DB exists | DB doesn't exist
* ------------------------------ | --------- | ------------------
* Xapian::DB_CREATE_OR_OPEN | open | create
* Xapian::DB_CREATE | fail | create
* Xapian::DB_CREATE_OR_OVERWRITE | overwrite | create
* Xapian::DB_OPEN | open | fail
*
* * at most one of the follow constants indicating which backend to
* use when creating a new database, ignored when opening or overwriting
* an existing database (default: currently Xapian::DB_BACKEND_GLASS):
*
* Constant | Meaning
* ------------------------------ | -----------------------
* Xapian::DB_BACKEND_GLASS | Create a glass database
* Xapian::DB_BACKEND_INMEMORY | Create inmemory DB (ignores @a path)
*
* * any number of the following flags:
*
* - Xapian::DB_NO_SYNC don't call fsync() or similar
* - Xapian::DB_FULL_SYNC try harder to ensure data is safe
* - Xapian::DB_DANGEROUS don't be crash-safe, no concurrent readers
* - Xapian::DB_NO_TERMLIST don't use a termlist table
* - Xapian::DB_RETRY_LOCK to wait to get a write lock
*
* @param block_size The block size in bytes to use when creating a
* new database. This is ignored when opening an
* existing database, and by backends which don't
* have the concept of a block size. The glass
* backend allows block sizes which are a power of
* 2 between 2048 and 65536 (inclusive) and its
* default (also used instead of an invalid value)
* is 8192 bytes.
*
* @exception Xapian::DatabaseLockError is thrown if the database's
* write lock could not be acquired.
* @exception Xapian::DatabaseOpeningError if the specified database
* cannot be opened
* @exception Xapian::DatabaseVersionError if the specified database has
* a format too old or too new to be supported.
*/
explicit WritableDatabase(std::string_view path,
int flags = 0,
int block_size = 0);
/** @private @internal Create a WritableDatabase given its internals. */
XAPIAN_VISIBILITY_INTERNAL
explicit WritableDatabase(Database::Internal* internal_)
: Database(internal_) {}
/** Copy constructor.
*
* The internals are reference counted, so copying is cheap.
*/
WritableDatabase(const WritableDatabase& o) : Database(o) {}
/** Assignment operator.
*
* The internals are reference counted, so assignment is cheap.
*/
WritableDatabase& operator=(const WritableDatabase& o) {
Database::operator=(o);
return *this;
}
/// Move constructor.
WritableDatabase(WritableDatabase&& o) : Database(std::move(o)) {}
/// Move assignment operator.
WritableDatabase& operator=(WritableDatabase&& o) {
Database::operator=(std::move(o));
return *this;
}
/** Commit pending modifications.
*
* Updates to a Xapian database are more efficient when applied in bulk,
* so by default Xapian stores modifications in memory until a threshold
* is exceeded and then they are committed to disk.
*
* When the database is closed (by an explicit call to close() or its
* destructor being called) then commit() is implicitly called unless
* a transaction is active.
*
* You can force any such pending modifications to be committed by calling
* this method, but bear in mind that the batching happens for a reason
* and calling commit() a lot is likely to slow down indexing.
*
* If the commit operation succeeds then the changes are reliably written
* to disk and available to readers. If the commit operation fails, then
* any pending modifications are discarded.
*
* However, note that if called on a sharded database, atomicity isn't
* guaranteed between shards - it's possible for the changes to one
* shard to be committed but changes to another shard to fail.
*
* It's not valid to call commit() within a transaction - see
* begin_transaction() for more details of how transactions work in
* Xapian.
*
* Currently batched modifications are automatically committed every
* 10000 documents added, deleted, or modified. This value is rather
* conservative, and if you have a machine with plenty of memory,
* you can improve indexing throughput dramatically by setting
* XAPIAN_FLUSH_THRESHOLD in the environment to a larger value.
*
* @since This method was new in Xapian 1.1.0 - in earlier versions it
* was called flush().
*/
void commit();
/** Begin a transaction.
*
* A Xapian transaction is a set of consecutive modifications to be
* committed as an atomic unit - in any committed revision of the
* database either none are present or they all are.
*
* However, note that if called on a sharded database, atomicity isn't
* guaranteed between shards. Within each shard, the transaction will
* still act atomically.
*
* A transaction is started with begin_transaction() and can either be
* completed by calling commit_transaction() or aborted by calling
* cancel_transaction().
*
* Closing the database (by an explicit call to close() or by its
* destructor being called) when a transaction is active will implicitly
* call cancel_transaction() to abort the transaction and discard the
* changes in it.
*
* By default, commit() is implicitly called by begin_transaction() and
* commit_transaction() so that the changes in the transaction are
* committed or not independent of changes before or after it.
*
* The downside of these implicit calls to commit() is that small
* transactions can harm indexing performance in the same way that
* explicitly calling commit() frequently can.
*
* If you're applying atomic groups of changes and only wish to ensure
* that each group is either applied or not applied, then you can prevent
* the automatic commit() before and after the transaction by starting the
* transaction with begin_transaction(false). However, if
* cancel_transaction() is called (or if commit_transaction() isn't called
* before the WritableDatabase object is destroyed) then any changes which
* were pending before the transaction began will also be discarded.
*
* @param flushed Is this a flushed transaction? By default transactions
* are "flushed", which means that committing a
* transaction will ensure those changes are permanently
* written to the database. By contrast, unflushed
* transactions only ensure that changes within the
* transaction are either all applied or all aren't.
*
* @exception Xapian::UnimplementedError is thrown if this is an InMemory
* database, which don't currently support transactions.
* @exception Xapian::InvalidOperationError will be thrown if a transaction
* is already active.
*/
void begin_transaction(bool flushed = true);
/** Complete the transaction currently in progress.
*
* If the transaction was begun as a flushed transaction then the changes
* in it have been committed to the database upon successful completion
* of this method.
*
* If an exception is thrown, then the changes in the transaction will be
* discarded (if the transaction was not begun as a flushed transaction,
* any changes made but not committed before begin_transaction() will also
* be discarded).
*
* In all cases the transaction will no longer be in progress.
*
* Note that if called on a sharded database, atomicity isn't guaranteed
* between shards. Within each shard, the transaction will still act
* atomically.
*
* @exception Xapian::UnimplementedError is thrown if this is an InMemory
* database, which don't currently support transactions.
* @exception Xapian::InvalidOperationError is thrown if no transaction
* was active.
*/
void commit_transaction() { end_transaction_(true); }
/** Abort the transaction currently in progress.
*
* Changes made within the current transaction will be discarded (if the
* transaction was not begun as a flushed transaction, any changes made
* but not committed before begin_transaction() will also be discarded).
*
* @exception Xapian::UnimplementedError is thrown if this is an InMemory
* database, which don't currently support transactions.
* @exception Xapian::InvalidOperationError is thrown if no transaction
* was active.
*/
void cancel_transaction() { end_transaction_(false); }
/** Add a document to the database.
*
* The document is allocated document ID (get_lastdocid() + 1) - the
* next highest document ID which has never previously been used by
* this database (so docids from deleted documents won't be reused).
*
* If you want to specify the document ID to be used, you should
* call replace_document() instead.
*
* If a transaction is active, the document addition is added to the
* transaction; otherwise it is added to the current batch of changes.
* Either way, it won't be visible to readers right away (unless we're
* not in a transaction and the addition triggers an automatic commit).
*
* @param doc The Document object to be added.
*
* @return The document ID allocated to the document.
*/
Xapian::docid add_document(const Xapian::Document& doc);
/** Delete a document from the database.
*
* This method removes the document with the specified document ID
* from the database.
*
* If a transaction is active, the document removal is added to the
* transaction; otherwise it is added to the current batch of changes.
* Either way, it won't be visible to readers right away (unless we're
* not in a transaction and the addition triggers an automatic commit).
*
* @param did The document ID of the document to be removed.
*/
void delete_document(Xapian::docid did);
/** Delete any documents indexed by a term from the database.
*
* This method removes any documents indexed by the specified term
* from the database.
*
* A major use is for convenience when UIDs from another system are
* mapped to terms in Xapian, although this method has other uses
* (for example, you could add a "deletion date" term to documents at
* index time and use this method to delete all documents due for
* deletion on a particular date).
*
* @param unique_term The term to remove references to.
*
* @since 2.0.0 The changes made by this method are made atomically.
* Previously automatic commits could happen during the
* batch.
*/
void delete_document(std::string_view unique_term);
/** Replace a document in the database.
*
* This method replaces the document with the specified document ID.
* If document ID @a did isn't currently used, the document will be
* added with document ID @a did.
*
* The monotonic counter used for automatically allocating document
* IDs is increased so that the next automatically allocated document
* ID will be did + 1. Be aware that if you use this method to
* specify a high document ID for a new document, and also use
* WritableDatabase::add_document(), Xapian may get to a state where
* this counter wraps around and will be unable to automatically
* allocate document IDs!
*
* Note that changes to the database won't be immediately committed to
* disk; see commit() for more details.
*
* @param did The document ID of the document to be replaced.
* @param document The new document.
*/
void replace_document(Xapian::docid did, const Xapian::Document& document);
/** Replace any documents matching a term.
*
* This method replaces any documents indexed by the specified term
* with the specified document. If any documents are indexed by the
* term, the lowest document ID will be used for the document,
* otherwise a new document ID will be generated as for add_document.
*
* One common use is to allow UIDs from another system to easily be
* mapped to terms in Xapian. Note that this method doesn't
* automatically add unique_term as a term, so you'll need to call
* document.add_term(unique_term) first when using replace_document()
* in this way.
*
* Note that changes to the database won't be immediately committed to
* disk; see commit() for more details.
*
* @param unique_term The "unique" term.
* @param document The new document.
*
* @return The document ID used by the new document. If term existed
* in the database, this will be the first document ID that
* was indexed by that term; otherwise the database allocates
* (get_lastdocid() + 1) as it does for add_document().
*
* @since 2.0.0 The changes made by this method are made atomically.
* Previously automatic commits could happen during the
* batch.
*/
Xapian::docid replace_document(std::string_view unique_term,
const Xapian::Document& document);
/** Add a word to the spelling dictionary.
*
* If the word is already present, its frequency is increased.
*
* @param word The word to add.
* @param freqinc How much to increase its frequency by (default 1).
*/
void add_spelling(std::string_view word,
Xapian::termcount freqinc = 1) const;
/** Remove a word from the spelling dictionary.
*
* The word's frequency is decreased, and if would become zero or less
* then the word is removed completely.
*
* @param word The word to remove.
* @param freqdec How much to decrease its frequency by (default 1).
*
* @return Any "unused" freqdec (if the word's frequency was less than
* freqdec then the difference is returned, else 0 is returned).
* Prior to 2.0.0 this method had void return type.
*/
termcount remove_spelling(std::string_view word,
termcount freqdec = 1) const;
/** Add a synonym for a term.
*
* @param term The term to add a synonym for.
* @param synonym The synonym to add. If this is already a synonym for
* @a term, then no action is taken.
*/
void add_synonym(std::string_view term,
std::string_view synonym) const;
/** Remove a synonym for a term.
*
* @param term The term to remove a synonym for.
* @param synonym The synonym to remove. If this isn't currently a
* synonym for @a term, then no action is taken.
*/
void remove_synonym(std::string_view term,
std::string_view synonym) const;
/** Remove all synonyms for a term.
*
* @param term The term to remove all synonyms for. If the term has
* no synonyms, no action is taken.
*/
void clear_synonyms(std::string_view term) const;
/** Set the user-specified metadata associated with a given key.
*
* This method sets the metadata value associated with a given key. If
* there is already a metadata value stored in the database with the same
* key, the old value is replaced. If you want to delete an existing item
* of metadata, just set its value to the empty string.
*
* User-specified metadata allows you to store arbitrary information in
* the form of (key, value) pairs.
*
* There's no hard limit on the number of metadata items, or the size of
* the metadata values. Metadata keys have a limited length, which depend
* on the backend. We recommend limiting them to 200 bytes. Empty keys
* are not valid, and specifying one will cause an exception.
*
* Metadata modifications are committed to disk in the same way as
* modifications to the documents in the database are: i.e., modifications
* are atomic, and won't be committed to disk immediately (see commit()
* for more details). This allows metadata to be used to link databases
* with versioned external resources by storing the appropriate version
* number in a metadata item.
*
* You can also use the metadata to store arbitrary extra information
* associated with terms, documents, or postings by encoding the termname
* and/or document id into the metadata key.
*
* @param key The key of the metadata item to set.
*
* @param metadata The value of the metadata item to set.
*
* @exception Xapian::DatabaseError will be thrown if a problem occurs
* while writing to the database.
*
* @exception Xapian::DatabaseCorruptError will be thrown if the database
* is in a corrupt state.
*
* @exception Xapian::InvalidArgumentError will be thrown if the key
* supplied is empty.
*
* @exception Xapian::UnimplementedError will be thrown if the database
* backend in use doesn't support user-specified metadata.
*/
void set_metadata(std::string_view key, std::string_view metadata);
/// Return a string describing this object.
std::string get_description() const;
};
}
#endif // XAPIAN_INCLUDED_DATABASE_H