多元索引路由字段的使用

创建多元索引时,您可以选择部分主键列作为路由字段,在进行索引数据写入时,表格存储会根据路由字段的值计算索引数据的分布位置,路由字段的值相同的记录会被索引到相同的数据分区中。

使用流程

  1. 创建索引时,指定一个或多个路由字段。

    您在创建多元索引时指定了路由字段后,索引数据的读写都会使用该路由字段进行定位。

    多元索引的路由键支持动态改变。如果想使用系统默认路由(即主键列路由)或者重新指定其他字段为路由字段,您可以通过动态修改schema功能实现路由键修改。更多信息,请参见动态修改schema

    重要

    路由字段只能是表格存储的主键列。

  2. 在索引查询时,在查询请求中指定路由字段值。

    查询数据时使用路由定向搜索指定数据分区,可以减少长尾对延迟的影响。对于自定义路由的查询请求,都要求用户提供路由字段。如不指定路由键,虽然查询结果一样,但查询时会访问无关的数据分区,浪费系统资源,增加访问延迟。

    重要

    路由键可配置为单值或多值,不支持范围。

使用方式

您可以使用控制台、命令行工具或者SDK进行路由键配置。路由键支持在创建多元索引时配置或者在创建多元索引后修改。此处以创建多元索引时配置路由键为例介绍。

说明

在创建多元索引后,如需修改多元索引的路由键,请通过动态修改schema实现。具体操作,请参见动态修改schema

  • 已创建数据表,且数据表的最大版本数(max Versions)必须为1,数据生命周期(Time to Live)必须满足如下条件中的任意一个。具体操作,请参见数据表操作

    • 数据表的数据生命周期为-1(数据永不过期)。

    • 数据表的数据生命周期不为-1时,数据表为禁止更新状态(即是否允许更新)。

  • 使用SDK方式进行操作时,还需要完成初始化Client。具体操作,请参见初始化OTSClient

  • 使用命令行工具方式进行操作前,还需要完成下载并启动命令行工具,然后配置接入实例信息。具体操作,请参见下载命令行工具启动并配置接入实例

使用控制台

表格存储控制台创建多元索引时,打开高级选项开关并进行路由键配置,如下图所示。具体操作,请参见创建多元索引

image

使用命令行工具

通过命令行工具执行create_search_index命令创建多元索引。更多信息,请参见多元索引

  1. 创建多元索引时指定路由键。

    以下示例用于创建名称为mysearchindex的多元索引,该多元索引有gid(long类型)、uid(long类型)、col2(long类型)、col3(text类型)、col1(keyword类型)何col3V(long类型)字段。其中col3V为虚拟列,对应原始列为col3。多元索引的路由键配置为uid。

    create_search_index -n mysearchindex

    根据系统提示输入索引schema,请根据实际字段修改示例后再使用。示例如下:

    {
    
        "IndexSetting": {
            "RoutingFields": ["uid"]
        },
        "FieldSchemas": [
        {
            "FieldName": "gid",
            "FieldType": "LONG",
            "Index": true,
            "EnableSortAndAgg": true,
            "Store": true,
            "IsArray": false,
            "IsVirtualField": false
        },
        {
            "FieldName": "uid",
            "FieldType": "LONG",
            "Index": true,
            "EnableSortAndAgg": true,
            "Store": true,
            "IsArray": false,
            "IsVirtualField": false
        },
        {
            "FieldName": "col2",
            "FieldType": "LONG",
            "Index": true,
            "EnableSortAndAgg": true,
            "Store": true,
            "IsArray": false,
            "IsVirtualField": false
        },
        {
            "FieldName": "col3",
            "FieldType": "TEXT",
            "Index": true,
            "Analyzer": "single_word",
            "AnalyzerParameter": {
            "CaseSensitive": true,
                "DelimitWord": null
            },
            "EnableSortAndAgg": false,
            "Store": true,
            "IsArray": false,
            "IsVirtualField": false
        },
        {
            "FieldName": "col1",
            "FieldType": "KEYWORD",
            "Index": true,
            "EnableSortAndAgg": true,
            "Store": true,
            "IsArray": false,
            "IsVirtualField": false
        },
        {
            "FieldName": "col3V",
            "FieldType": "LONG",
            "Index": true,
            "EnableSortAndAgg": true,
            "Store": true,
            "IsArray": false,
            "IsVirtualField": true,
            "SourceFieldNames": [
            "col3"
            ]
        }]
    }
  2. 使用多元索引查询数据时指定路由键。

    以下示例用于使用mysearchindex查询col2列小于200的行数据。查询时带有多元索引路由键uid。

    search -n search_index --return_all_indexed

    根据系统提示输入查询条件,请根据实际字段修改示例后再使用。示例如下:

    说明

    此处以RangeQuery(范围查询)为例介绍,如需使用其他查询方式,请参见多元索引基础功能

    {
        "Offset": -1,
        "Limit": 10,
        "Collapse": null,
        "Sort": null,
        "GetTotalCount": true,
        "Token": null,
    	  "IndexSetting": {
            "RoutingFields": ["uid"]
        },
        "Query": {
            "Name": "RangeQuery",
            "Query": {
                "FieldName": "col2",
                "From": null,
                "To": 200,
                "IncludeLower": false,
                "IncludeUpper": false
             }
         }
    }

使用SDK

您可以使用Java SDKGo SDKPython SDKNode.js SDK.NET SDKPHP SDK在创建多元索引时配置路由键。此处以Java SDK为例介绍路由键的配置和使用。

以下示例用于创建order数据表时创建order_index多元索引并指定路由字段为user_id字段。然后写入数据并带上路由字段进行查询。该数据表有order_id(string类型)和user_id(string类型);该多元索引有product_name(keyword类型)、order_time(long类型)和user_id(keyword类型)字段,多元索引的路由键为user_id字段。

private static void testRoute(SyncClient client) throws InterruptedException {
    //创建表。
    TableMeta meta = new TableMeta("order");
    meta.addPrimaryKeyColumn("order_id",PrimaryKeyType.STRING);
    meta.addPrimaryKeyColumn("user_id",PrimaryKeyType.STRING);
    TableOptions options = new TableOptions();
    options.setMaxVersions(1);
    options.setTimeToLive(-1);
    CreateTableRequest request = new CreateTableRequest(meta,options);
    request.setReservedThroughput(new ReservedThroughput(new CapacityUnit(0, 0)));
    CreateTableResponse response = client.createTable(request);

    //创建多元索引并指定路由字段。
    CreateSearchIndexRequest searchIndexRequest = new CreateSearchIndexRequest();
    //订单表。
    searchIndexRequest.setTableName("order"); 
    //订单表索引名。
    searchIndexRequest.setIndexName("order_index"); 
    IndexSchema indexSchema = new IndexSchema();
    IndexSetting indexSetting = new IndexSetting();
    //设置user_id为路由字段。
    indexSetting.setRoutingFields(Arrays.asList("user_id"));
    indexSchema.setIndexSetting(indexSetting);

    //添加索引字段。此处只是给出示例,您可以根据业务需求添加索引字段。
    indexSchema.setFieldSchemas(Arrays.asList(
        new FieldSchema("product_name",FieldType.KEYWORD).setStore(true).setIndex(true),
        new FieldSchema("order_time",FieldType.LONG).setStore(true).setEnableSortAndAgg(true).setIndex(true),
        new FieldSchema("user_id",FieldType.KEYWORD).setStore(true).setIndex(true)
    ));

    searchIndexRequest.setIndexSchema(indexSchema);
    client.createSearchIndex(searchIndexRequest);
    //等待数据表加载。
    Thread.sleep(6*1000); 

    //插入一些测试数据。

    String[] productName = new String[]{"product a", "product b", "product c"};
    String[] userId = new String[]{"00001", "00002", "00003", "00004", "00005"};
    for (int i = 0; i < 100; i++){

      PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
      primaryKeyBuilder.addPrimaryKeyColumn("order_id",PrimaryKeyValue.fromString(i+""));
      primaryKeyBuilder.addPrimaryKeyColumn("user_id",PrimaryKeyValue.fromString(userId[i%(userId.length)]));
      PrimaryKey primaryKey = primaryKeyBuilder.build();

      RowPutChange rowPutChange = new RowPutChange("order",primaryKey);

      //写入属性列。
      rowPutChange.addColumn("product_name",ColumnValue.fromString(productName[i%(productName.length)]));
      rowPutChange.addColumn("order_time",ColumnValue.fromLong(System.currentTimeMillis()));
      rowPutChange.setCondition(new Condition(RowExistenceExpectation.IGNORE));

      client.putRow(new PutRowRequest(rowPutChange));

    }
    //等待数据同步到多元索引。
    Thread.sleep(20*1000);

    //带上路由字段的查询。
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.setTableName("order");
    searchRequest.setIndexName("order_index");
    MatchQuery matchQuery = new MatchQuery();
    matchQuery.setFieldName("user_id");
    matchQuery.setText("00002");
    SearchQuery searchQuery = new SearchQuery();
    searchQuery.setQuery(matchQuery);
    searchQuery.setGetTotalCount(true);

    SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
    columnsToGet.setReturnAll(true);
    searchRequest.setColumnsToGet(columnsToGet);
    searchRequest.setSearchQuery(searchQuery);

    PrimaryKeyBuilder pkbuild = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    pkbuild.addPrimaryKeyColumn("user_id",PrimaryKeyValue.fromString("00002"));
    PrimaryKey routingValue = pkbuild.build();
    searchRequest.setRoutingValues(Arrays.asList(routingValue));
    SearchResponse searchResponse = client.search(searchRequest);

    System.out.println(searchResponse.isAllSuccess());
    System.out.println("totalCount:"+ searchResponse.getTotalCount());
    System.out.println("RowCount:"+searchResponse.getRows().size());

  }