索引是加速数据库查询的重要手段,Lindorm宽表除了提供高性能的二级索引外,同时支持全文索引(Search Index),主要面向复杂的多维查询场景,并能够覆盖模糊查询、聚合分析、排序、分页等场景。

简介

Lindorm宽表提供高性能的主键查询,如果业务方有非主键查询的需求,只能通过创建二级索引来满足,并且需要预先定义好索引列的顺序,一旦违背二级索引定义的顺序,将无法有效的完成查询。随着业务查询模型的增加,需要的二级索引也会越来越多,这将直接影响写入的吞吐,存储成本也会直线增加。基于倒排索引构建的Search Index有效的解决了这个问题,如果您有如下的需求,都可以直接创建Search Index使用:

  • 多维查询。给定多个列的随机组合,快速返回查询结果。
  • 统计分析。提供基础的统计能力,可以对指定列输出统计结果。
  • 排序。提供order by能力,返回结果按照任意指定列排序。

适用场景

Search Index适用于需要保存海量数据,并且需要各种条件组合查询的业务。例如:物流订单场景。

整体数据流

Search Index是宽表引擎和搜索引擎深度融合后提供的新型索引,数据写入Lindorm宽表后,内置的LTS(原BDS)负责将数据实时同步到搜索引擎中。在此架构下,宽表引擎、数据同步通道LTS和搜索引擎都是以独立服务的方式存在,您可以分别对各个引擎进行管理:如果搜索引擎处理能力不足,只需要扩容搜索引擎;如果LTS同步能力不足,可以单独扩容LTS。宽表引擎/LTS/搜索引擎可以针对不同的使用场景选择不同的机型,独立的部署形态大幅提升了系统的稳定性。整体数据流如下图。

search_index1

与二级索引的区别

Lindorm提供高性能原生二级索引,可以低成本的解决非主键查询问题,适用于查询列比较固定的场景。如果业务场景需要复杂的多维组合查询,需要考虑使用Search Index。

宽表数据延时

宽表数据同步到搜索引擎会有延时,以下介绍延时时间计算。

总的延时时间 = 数据同步延迟 + 索引可见时间
  • 同步延迟:一般同步延迟在200ms以内,可横向扩展LTS来降低延迟。
  • 索引可见时间:默认索引可见时间为15s,最低可以设置为1s。设置的越小,可能会导致索引文件积压,影响查询性能。建议通过实际测试来设置合理的值。具体可参见索引数据可见性

开通全文索引

开通宽表引擎后,可以直接开通全文索引功能,实例会自动开通搜索引擎LTS(原BDS)

宽表开通搜索

使用指南

Search Index核心的体验如下:
  • 与二级索引体验类似,客户端不感知索引表的存在。
  • 业务只需要查询主表,服务端会自动编译优化为索引访问,并进行数据的汇总,统一返回给客户端。
  • 可同时支持上千个列的索引。
  • 写入表中的数据会自动同步到索引中去,同步延迟在200ms以内。

Search Index支持标准CQL访问,使用举例:

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.PlainTextAuthProvider;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Session;

import java.io.IOException;

public class Test {

    public static void main(String[] argv) throws IOException, InterruptedException {
        String[] contactPoints = new String[]{
                "链接的地址(不要加端口号)"
        };
        Cluster cluster = null;
        try {
            Cluster.builder().addContactPoints(contactPoints).withAuthProvider(new PlainTextAuthProvider("账户", "密码")).build();
            cluster.init();
            Session session = cluster.connect();
            // 创建keyspace,建议在cqlsh 里面同步执行;
            session.execute("CREATE KEYSPACE kss WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};");
            // 创建table,建议在cqlsh 里面同步支持;如果是lindorm 多zone场景下,默认是需要指定一致性以及MUTABLE属性,一般使用如下配置,有疑问请问答疑,非多zone场景不需要设置
            session.execute("CREATE TABLE kss.tb ( cn1 text PRIMARY KEY , cn2 text , cn3 text )  WITH extensions = {'CONSISTENCY_TYPE':'strong', 'MUTABILITY':'MUTABLE_LATEST'};");

            //创建search index ,建议在cqlsh下创建, 指定index名字是tbidx,创建的列是cn2,cn3, 如果不指定WITH COLUMNS 或者 指定WITH COLUMNS (*)表示对所有列建索引;
            session.execute("CREATE SEARCH INDEX tbidx ON kss.tb WITH COLUMNS (cn2, cn3);");

            // rebuild 索引,创建完成以后必须build索引,支持同步和异步构建(指定关键字ASYNC),可以在建完索引后rebuild 也可以在写完部分数据后,开始查询前rebuild
            session.execute("REBUILD SEARCH INDEX ON kss.tb;"); //rebuild search index [ASYNC] on tablename;

            //写数据;
            session.execute("INSERT INTO kss.tb (cn1, cn2, cn3) VALUES ( 'v11', 'v12', 'v13');");
            session.execute("INSERT INTO kss.tb (cn1, cn2, cn3) VALUES ( 'v21', 'v22', 'v23');");
            session.execute("INSERT INTO kss.tb (cn1, cn2, cn3) VALUES ( 'v31', 'v32', 'v33');");

            //正常读数据;
            ResultSet resultSet = session.execute("select * from kss.tb");
            resultSet.forEach(System.out::println);             

            //命中主表
            resultSet = session.execute("select * from kss.tb WHERE cn1 = 'v11'");
            resultSet.forEach(System.out::println);

            //模糊匹配查询;
            resultSet = session.execute("select * from kss.tb where cn2 like 'v2' ");//match
            resultSet.forEach(System.out::println);
            resultSet = session.execute("select * from kss.tb where cn2 like '%v2' ");//前缀匹配,0到无穷字符串匹配
            resultSet.forEach(System.out::println);
            resultSet = session.execute("select * from kss.tb where cn2 like 'v2%' ");//后缀匹配,0到无穷字符串匹配
            resultSet.forEach(System.out::println);
            resultSet = session.execute("select * from kss.tb where cn2 like '%v2%' ");//前后匹配,0到无穷字符串匹配
            resultSet.forEach(System.out::println);

            //常见操作
            resultSet = session.execute("select * from kss.tb where cn2 > 'v20' order by cn3 ");//
            resultSet.forEach(System.out::println);

            //修改search index ,添加或者删除列
            session.execute("ALTER SEARCH INDEX SCHEMA  ON kss.tb ADD FIELD cn1;");//可以支持添加多个,ADD FIELD cn1, cn2, cn3
            session.execute("ALTER SEARCH INDEX SCHEMA  ON kss.tb DROP FIELD cn1;");//可以支持删除多个,DROP FIELD cn1, cn2, cn3
            // 修改完成以后执行一次rebuild search index

            session.execute("DROP SEARCH INDEX ON kss.tb");// DROP SEARCH INDEX on tablename;

        } finally {
            if (cluster != null)
                cluster.close();
        }

    }

}
            
说明 CQL访问Search Index的详细使用可钉钉咨询专家服务

使用限制

使用CQL操作Search Index核心的限制如下:
  • 暂时 不支持Group by
  • 模糊匹配like只支持任意字符'%'的前缀匹配,后缀匹配,前后缀匹配以及完全match