nosql中的index

cassandra中的SecondaryIndex的应用场景主要在于没有带着rowkey的查询。虽然带着rowkey的条件进行检索式cassandra这种非关系型数据库的主流检索,但是使用nosql DB的时候,往往一些统计功能,或者公共的功能,(例如关注度最高的微博,操作次数最多的操作等等)这些不需要和用户绑定,但是又是很多应用不可少的检索功能。并且在cassandra这种海量级的nosql DB中,如果没有Secondary Index这种功能提升没有带rowkey的查询性能的功能,那么就会丧失很多机会,让很多系统发展以后,都没有办法扩展自己的能力。

1、SecondaryIndex的结构

Secondary Index和所有的数据库的index一样是一个牺牲容量,换取某种查询性能的功能。系统会新建一个index表,来存放便于检索的数据,从而加快检索。而cassandra数据库的检索最成熟的条件,就是rowkey。所以Secondary index就是一个以index字段为rowkey,以数据表中的rowkey作为Column的StandCF。

在1.2版本的cassandra中实现的KeyIndex和CompositeIndex都是继承AbstractSimplePerColumnSecondaryIndex简单单列index的实现类。

public void init()
    {
        assert baseCfs != null && columnDefs != null && columnDefs.size() == 1;

        ColumnDefinition columnDef = columnDefs.iterator().next();
        init(columnDef);

        AbstractType indexComparator = SecondaryIndex.getIndexComparator(baseCfs.metadata, columnDef);
        CFMetaData indexedCfMetadata = CFMetaData.newIndexMetadata(baseCfs.metadata, columnDef, indexComparator);
        indexCfs = ColumnFamilyStore.createColumnFamilyStore(baseCfs.table,
                                                             indexedCfMetadata.cfName,
                                                             new LocalPartitioner(columnDef.getValidator()),
                                                             indexedCfMetadata);

        // enable and initialize row cache based on parent's setting and indexed column's cardinality
        CFMetaData.Caching baseCaching = baseCfs.metadata.getCaching();
        if (baseCaching == CFMetaData.Caching.ALL || baseCaching == CFMetaData.Caching.ROWS_ONLY)
        {
            /*
             * # of index CF's key = cardinality of indexed column.
             * if # of keys stored in index CF is more than average column counts (means tall table),
             * then consider it as high cardinality.
             */
            double estimatedKeys = indexCfs.estimateKeys();
            double averageColumnCount = indexCfs.getMeanColumns();
            if (averageColumnCount > 0 && estimatedKeys / averageColumnCount > 1)
            {
                logger.debug("turning row cache on for " + indexCfs.getColumnFamilyName());
                indexCfs.metadata.caching(baseCaching);
                indexCfs.initRowCache();
            }
        }
    }

2、SecondaryIndex表的属性

SecondaryIndex的CF的属性有:

属性名 属性值
keyspaceName 源CF的keyspaceName
CFType Standard CF
Rowkey的类型 index字段的类型
读修复概率 0
GC清理时间 0
keycache开启配置 如果源CF开启则开启
RowCache开启配置
compact策略 与源CF一致
compress策略 与源CF一致


public static CFMetaData newIndexMetadata(CFMetaData parent, ColumnDefinition info, AbstractType columnComparator)
    {
        // Depends on parent's cache setting, turn on its index CF's cache.
        // Here, only key cache is enabled, but later (in KeysIndex) row cache will be turned on depending on cardinality.
        Caching indexCaching = parent.getCaching() == Caching.ALL || parent.getCaching() == Caching.KEYS_ONLY
                             ? Caching.KEYS_ONLY
                             : Caching.NONE;

        return new CFMetaData(parent.ksName, parent.indexColumnFamilyName(info), ColumnFamilyType.Standard, columnComparator, null)
                             .keyValidator(info.getValidator())
                             .readRepairChance(0.0)
                             .dcLocalReadRepairChance(0.0)
                             .gcGraceSeconds(0)
                             .caching(indexCaching)
                             .compactionStrategyClass(parent.compactionStrategyClass)
                             .compactionStrategyOptions(parent.compactionStrategyOptions)
                             .reloadSecondaryIndexMetadata(parent);
    }


3、SecondaryIndex创建的条件

在普通的CF创建的时候,如果Column定义的时候,indexType属性可以为KEYS(即为KeyIndex),COMPOSITES(即为CompositeIndex),CUSTOM(即为用户自己二次开发的index功能)。

在1.2版本的cassandra中,目前只支持KeyIndex,主要是针对StandCF的普通Column的和CompositeIndex主要是针对CompositeCF的普通Column。

/**
     * Drops and adds new indexes associated with the underlying CF
     */
    public void reload()
    {
        // figure out what needs to be added and dropped.
        // future: if/when we have modifiable settings for secondary indexes,
        // they'll need to be handled here.
        Collection indexedColumnNames = indexesByColumn.keySet();
        for (ByteBuffer indexedColumn : indexedColumnNames)
        {
            ColumnDefinition def = baseCfs.metadata.getColumn_metadata().get(indexedColumn);
            if (def == null || def.getIndexType() == null)
                removeIndexedColumn(indexedColumn);
        }

        for (ColumnDefinition cdef : baseCfs.metadata.getColumn_metadata().values())
            if (cdef.getIndexType() != null && !indexedColumnNames.contains(cdef.name))
                addIndexedColumn(cdef);

        Set reloadedIndexes = Collections.newSetFromMap(new IdentityHashMap());
        for (SecondaryIndex index : indexesByColumn.values())
        {
            if (reloadedIndexes.add(index))
                index.reload();
        }
    }

4、SecondaryIndex的应用




5、SecondaryIndex与源数据表的关系

Secondary IndexCF都是每个节点自己的本地表,没有副本,所以当数据迁移的时候,需要重新生成对应的index数据。

(1)重启的时候,需要在加载数据表的时候,加载出对应的indexCF结构。这样就根据indexInfo系统表中有没有对应的indexCF的记录,判断indexCF是否需要生成index数据,如果IndexInfo系统表有对应的indexCF数据,则不需要重新生成indexCF的数据,如果没有,则需要重新生成。

问题:如果indexCF在生成对应的数据的时候,此时进行的index条件的查询,由于index数据还没有生成完全导致极大可能差不多数据。




你可能感兴趣的:(nosql中的index)