public interface Index
MyCustomIndex( ColumnFamilyStore baseCfs, IndexMetadata indexDef )
The main interface defines methods for index management, index selection at both write and query time,
as well as validation of values that will ultimately be indexed.
Two sub-interfaces are also defined, which represent single use helpers for short lived tasks at read and write time.
Indexer: an event listener which receives notifications at particular points during an update of a single partition
in the base table.
Searcher: performs queries against the index based on a predicate defined in a RowFilter. An instance
is expected to be single use, being involved in the execution of a single ReadCommand.
The main interface includes factory methods for obtaining instances of both of the sub-interfaces;
The methods defined in the top level interface can be grouped into 3 categories:
Management Tasks:
This group of methods is primarily concerned with maintenance of secondary indexes are are mainly called from
SecondaryIndexManager. It includes methods for registering and un-registering an index, performing maintenance
tasks such as (re)building an index from SSTable data, flushing, invalidating and so forth, as well as some to
retrieve general metadata about the index (index name, any internal tables used for persistence etc).
Several of these maintenance functions have a return type of Callable>; the expectation for these methods is
that any work required to be performed by the method be done inside the Callable so that the responsibility for
scheduling its execution can rest with SecondaryIndexManager. For instance, a task like reloading index metadata
following potential updates caused by modifications to the base table may be performed in a blocking way. In
contrast, adding a new index may require it to be built from existing SSTable data, a potentially expensive task
which should be performed asyncronously.
Index Selection:
There are two facets to index selection, write time and read time selection. The former is concerned with
identifying whether an index should be informed about a particular write operation. The latter is about providing
means to use the index for search during query execution.
Validation:
Values that may be written to an index are checked as part of input validation, prior to an update or insert
operation being accepted.
Sub-interfaces:
Update processing:
Indexes are subscribed to the stream of events generated by modifications to the base table. Subscription is
done via first registering the Index with the base table's SecondaryIndexManager. For each partition update, the set
of registered indexes are then filtered based on the properties of the update using the selection methods on the main
interface described above. Each of the indexes in the filtered set then provides an event listener to receive
notifications about the update as it is processed. As such then, a event handler instance is scoped to a single
partition update; SecondaryIndexManager obtains a new handler for every update it processes (via a call to the
factory method, indexerFor. That handler will then receive all events for the update, before being
discarded by the SecondaryIndexManager. Indexer instances are never re-used by SecondaryIndexManager and the
expectation is that each call to indexerFor should return a unique instance, or at least if instances can
be recycled, that a given instance is only used to process a single partition update at a time.
Search:
Each query (i.e. a single ReadCommand) that uses indexes will use a single instance of Index.Searcher. As with
processing of updates, an Index must be registered with the primary table's SecondaryIndexManager to be able to
support queries. During the processing of a ReadCommand, the Expressions in its RowFilter are examined to determine
whether any of them are supported by a registered Index. supportsExpression is used to filter out Indexes which
cannot support a given Expression. After filtering, the set of candidate indexes are ranked according to the result
of getEstimatedResultRows and the most selective (i.e. the one expected to return the smallest number of results) is
chosen. A Searcher instance is then obtained from the searcherFor method & used to perform the actual Index lookup.
Finally, Indexes can define a post processing step to be performed on the coordinator, after results (partitions from
the primary table) have been received from replicas and reconciled. This post processing is defined as a
java.util.functions.BiFunctionpublic static MapThe input is the map of index options supplied in the WITH clause of a CREATE INDEX statement.validateOptions(Map options);
{@code public static MapIn this version, the base table's metadata is also supplied as an argument. If both overloaded methods are provided, only the one including the base table's metadata will be invoked. The validation method should return a map containing any of the supplied options which are not valid for the implementation. If the returned map is not empty, validation is considered failed and an error is raised. Alternatively, the implementation may choose to throw an org.apache.cassandra.exceptions.ConfigurationException if invalid options are encountered.validateOptions(Map options, CFMetaData cfm);}
Modifier and Type | Interface and Description |
---|---|
static interface |
Index.Indexer
Listener for processing events emitted during a single partition update.
|
static interface |
Index.Searcher
Performs the actual index lookup during execution of a ReadCommand.
|
Modifier and Type | Method and Description |
---|---|
AbstractType<?> |
customExpressionValueType()
If the index supports custom search expressions using the
SELECT * FROM table WHERE expr(index_name, expression) syntax, this
method should return the expected type of the expression argument.
|
boolean |
dependsOn(ColumnDefinition column)
Called to determine whether this index targets a specific column.
|
java.util.Optional<ColumnFamilyStore> |
getBackingTable()
If the index implementation uses a local table to store its index data this method should return a
handle to it.
|
java.util.concurrent.Callable<?> |
getBlockingFlushTask()
Return a task which performs a blocking flush of the index's data to persistent storage.
|
long |
getEstimatedResultRows()
Return an estimate of the number of results this index is expected to return for any given
query that it can be used to answer.
|
IndexMetadata |
getIndexMetadata()
Returns the IndexMetadata which configures and defines the index instance.
|
java.util.concurrent.Callable<?> |
getInitializationTask()
Return a task to perform any initialization work when a new index instance is created.
|
java.util.concurrent.Callable<?> |
getInvalidateTask()
Return a task which invalidates the index, indicating it should no longer be considered usable.
|
java.util.concurrent.Callable<?> |
getMetadataReloadTask(IndexMetadata indexMetadata)
Return a task to reload the internal metadata of an index.
|
RowFilter |
getPostIndexQueryFilter(RowFilter filter)
Transform an initial RowFilter into the filter that will still need to applied
to a set of Rows after the index has performed it's initial scan.
|
java.util.concurrent.Callable<?> |
getTruncateTask(long truncatedAt)
Return a task to truncate the index with the specified truncation timestamp.
|
Index.Indexer |
indexerFor(DecoratedKey key,
PartitionColumns columns,
int nowInSec,
OpOrder.Group opGroup,
IndexTransaction.Type transactionType)
Creates an new
Indexer object for updates to a given partition. |
java.util.function.BiFunction<PartitionIterator,ReadCommand,PartitionIterator> |
postProcessorFor(ReadCommand command)
Return a function which performs post processing on the results of a partition range read command.
|
void |
register(IndexRegistry registry)
An index must be registered in order to be able to either subscribe to update events on the base
table and/or to provide Searcher functionality for reads.
|
Index.Searcher |
searcherFor(ReadCommand command)
Factory method for query time search helper.
|
boolean |
shouldBuildBlocking()
Return true if this index can be built or rebuilt when the index manager determines it is necessary.
|
boolean |
supportsExpression(ColumnDefinition column,
Operator operator)
Called to determine whether this index can provide a searcher to execute a query on the
supplied column using the specified operator.
|
default boolean |
supportsReplicaFilteringProtection(RowFilter rowFilter)
Tells whether this index supports replica fitering protection or not.
|
void |
validate(PartitionUpdate update)
Called at write time to ensure that values present in the update
are valid according to the rules of all registered indexes which
will process it.
|
default void |
validate(ReadCommand command)
Used to validate the various parameters of a supplied ReadCommand,
this is called prior to execution.
|
java.util.concurrent.Callable<?> getInitializationTask()
IndexMetadata getIndexMetadata()
java.util.concurrent.Callable<?> getMetadataReloadTask(IndexMetadata indexMetadata)
void register(IndexRegistry registry)
registry
- the index registry to register the instance withjava.util.Optional<ColumnFamilyStore> getBackingTable()
java.util.concurrent.Callable<?> getBlockingFlushTask()
java.util.concurrent.Callable<?> getInvalidateTask()
java.util.concurrent.Callable<?> getTruncateTask(long truncatedAt)
truncatedAt
- timestamp of the truncation operation. This will be the same timestamp used
in the truncation of the base table.boolean shouldBuildBlocking()
boolean dependsOn(ColumnDefinition column)
column
- the column definition to checkboolean supportsExpression(ColumnDefinition column, Operator operator)
column
- the target column of a search query predicateoperator
- the operator of a search query predicateAbstractType<?> customExpressionValueType()
RowFilter getPostIndexQueryFilter(RowFilter filter)
filter
- the intial filter belonging to a ReadCommandlong getEstimatedResultRows()
void validate(PartitionUpdate update) throws InvalidRequestException
update
- PartitionUpdate containing the values to be validated by registered Index implementationsInvalidRequestException
Index.Indexer indexerFor(DecoratedKey key, PartitionColumns columns, int nowInSec, OpOrder.Group opGroup, IndexTransaction.Type transactionType)
Indexer
object for updates to a given partition.key
- key of the partition being modifiedcolumns
- the regular and static columns the created indexer will have to deal with.
This can be empty as an update might only contain partition, range and row deletions, but
the indexer is guaranteed to not get any cells for a column that is not part of columns
.nowInSec
- current time of the update operationopGroup
- operation group spanning the update operationtransactionType
- indicates what kind of update is being performed on the base data
i.e. a write time insert/update/delete or the result of compactionnull
if the index is not interested by the update
(this could be because the index doesn't care about that particular partition, doesn't care about
that type of transaction, ...).default void validate(ReadCommand command) throws InvalidRequestException
command
- a ReadCommand whose parameters are to be verifiedInvalidRequestException
- if the details of the command fail to meet the
index's validation rulesdefault boolean supportsReplicaFilteringProtection(RowFilter rowFilter)
ALLOW FILTERING
and without using the index. This means that index
implementations using custom query syntax or applying transformations to the indexed data won't support it.
See CASSANDRA-8272 for further details.rowFilter
- rowFilter of query to decide if it supports replica filtering protection or notjava.util.function.BiFunction<PartitionIterator,ReadCommand,PartitionIterator> postProcessorFor(ReadCommand command)
Index.Searcher searcherFor(ReadCommand command)
command
- the read command being executedCopyright © 2022 The Apache Software Foundation