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

简介

Lindorm宽表提供高性能的主键查询,如果业务方有非主键查询的需求,只能通过创建二级索引来满足,并且需要预先定义好索引列的顺序,一旦违背二级索引定义的顺序,将无法有效的完成查询。随着业务查询模型的增加,需要的二级索引也会越来越多,这将直接影响写入的吞吐,存储成本也会直线增加。全文索引功能有效的解决了这个问题,如果您有如下的需求,都可以通过全文索引来实现。
  • 多维查询。给定多个列的随机组合,快速返回查询结果。
  • 统计分析。提供基础的统计能力,可以对指定列输出统计结果。
  • 排序。提供order by能力,返回结果按照任意指定列排序。

适用场景

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

整体数据流

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

search_index1

全文索引与二级索引的区别

Lindorm支持二级索引功能,二级索引功能可以低成本的解决非主键查询问题,适用于查询列比较固定的场景。但是在复杂的多维组合查询场景下,需要考虑使用全文索引。

使用优势

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

宽表数据延时

宽表数据同步到搜索引擎会有延时,延时时间的计算方法:总的延时时间 = 数据同步延迟 + 索引可见时间。

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

开通全文索引

开通全文索引功能,具体操作请参见开通全文索引

通过Java API连接并使用全文索引

  1. 下载Lindorm客户端。下述语句是通过Maven依赖下载Lindorm客户端。
    <dependency>
    <groupId>com.aliyun.lindorm</groupId>
    <artifactId>lindorm-all-client</artifactId>
    <version>2.0.7</version>
    </dependency>
  2. 初始化Lindorm客户端。
    String LINDORM_JDBC_URL =  "控制台获取的Lindorm宽表SQL地址"; 
    String LINDORM_USER = "user"; 
    String LINDORM_PASSWORD = "password"; 
    String USER_NAME = "用户名"; 
    String PASSWORD = "密码"; 
    Properties properties = new Properties(); 
    properties.put(LINDORM_USER, USER_NAME); 
    properties.put(LINDORM_PASSWORD, PASSWORD);
  3. 建立Lindorm客户端和数据之间连接。
    pconn= new LqlDriver().connect(LINDORM_JDBC_URL, properties); 
    或者
    pconn = DriverManager.getConnection(LINDORM_JDBC_URL, properties);
  4. 通过Java API使用全文索引。下面提供一些简单的Java示例。
    //如果没有schema,则需要先创建
    create schema test;
    
    //指定已有的或者新创建的schema
    use test;
    //创建表 
    Statement stmt = pconn.createStatement();
    String tableName = "sql_table_" + new Random().nextInt(1000);
    String tableName = "sql_table_" + new Random().nextInt(1000);
    String createTable = "create table if not exists " + tableName +
    " (p1 varchar,p2 varchar,c1 varchar,c2 varchar, c3 varchar, c4 varchar, c5 varchar, constraint primary key (p1,p2 desc)) "
    + "with (MUTABILITY='IMMUTABLE',CONSISTENCY='strong')";
    stmt.executeUpdate(createTable);
    
    //创建search index
    String indexName = "idx" + new Random().nextInt(1000);
    String createSearchIndex = "create search index if not exists " + indexName + " on "+ tableName + "(c1,c2,c3)";
    stmt.executeUpdate(createSearchIndex);
    
    //通过show search index, 确认search index 是否创建成功
    String showSearchIndex = "show search index from "+ tableName;
    ResultSet rs = stmt.executeQuery(showSearchIndex);
    
    while(rs.next()){
      String c1 = rs.getString(1);
      String c2 = rs.getString(2);
      String c3 = rs.getString(3);
      String c4 = rs.getString(4);
      String c5 = rs.getString(5);
      String c7 = rs.getString(7);
      System.out.println("TABLE_SCHEMA:"+c1+",DATA_TABLE:"+c2+",INDEX_NAME:"+c3+",INDEX_STATE:"+c4+",INDEX_TYPE:"+c5+",INDEX_COLUMN:"+ c7);
    }
    
    //写数据
    
    String unsertData = "upsert into " + tableName + "(p1,p2,c1,c2,c3) values('1', '456789', '张三', '25', '男')";
    stmt.executeUpdate(unsertData);
    unsertData = "upsert into " + tableName + "(p1,p2,c1,c2,c3) values('2', '123456', '李四', '30', '男')";
    stmt.executeUpdate(unsertData);
    
    
    //以索引列为查询条件,读取数据
    String queryData = "select p1,p2,c1,c2,c3 from " + tableName + " where c1 = '张三' and c2 = '25' and c3 = '男' allow filtering ";
    ResultSet rsSelect = stmt.executeQuery(queryData);
    while(rsSelect.next()){
      String p1 = rsSelect.getString(1);
      String p2 = rsSelect.getString(2);
      String c1 = rsSelect.getString(3);
      String c2 = rsSelect.getString(4);
      String c3 = rsSelect.getString(5);
      System.out.println("p1:"+p1+",p2:"+p2+",c1:"+c1+",c2:"+c2+",c3:"+c3);
    }
    
    //删除search index
    String alterSearchIndexState = "alter search index if exists " + indexName + " on "+ tableName + " DISABLED";
    stmt.executeUpdate(alterSearchIndexState);
    String dropSearchIndex = "drop search index if exists " + indexName + " on " + tableName;
    stmt.executeUpdate(dropSearchIndex);
      
    // cleanup
    stmt.executeUpdate("offline table " + tableName);
    stmt.executeUpdate("drop table " + tableName);
    stmt.close();
    说明 使用特定的schema,在使用前需要执行use schema语句。