创建多元索引

通过控制台、命令行或SDK您可以为某一个表创建一个或多个多元索引,然后使用多元索引对表中的数据进行查询和简单分析。

最佳使用方式

请根据实际查询需求确定在一张数据表中创建多元索引的个数。

例如一张数据表有5个字段,分别为id、name、age、city、sex,需要按照name、agecity查询数据时,有两种创建多元索引的方式。

  • 方法一:一个字段建立一个多元索引

    按照name、agecity字段分别创建多元索引,名称分别为name_index、age_index、city_index。

    • 如果按照城市查询学生,则查询city_index,如果按照年龄查询学生,则查询age_index。

    • 如果查询年龄小于12岁且城市是成都的学生,此种方式就无法查询。

    此方式的实现类似于全局二级索引,使用此方式创建多元索引会带来更高的费用,因此不建议使用此方式创建多元索引。

  • 方法二(推荐):多个字段创建在一个多元索引中

    name、agecity字段创建在一个多元索引中,名称为student_index。

    • 如果按照城市查询学生,则查询student_indexcity字段;如果按照年龄查询学生,则查询student_indexage字段。

    • 如果查询年龄小于12岁且城市是成都的学生,则查询student_indexagecity字段。

    此方式才能发挥多元索引最大优势,不仅功能更丰富,而且价格会更低。极力推荐使用此方式创建多元索引。

使用限制

  • 创建索引的时效性

    创建多元索引后,需要等几秒钟才能使用,但是此过程中不影响数据写入,只影响索引元信息的查询和索引查询。

  • 创建多元索引时,请确保多元索引中的字段类型与表中的字段类型相匹配。更多信息,请参见基础数据类型及映射

  • 数量限制

    更多信息,请参见多元索引限制

参数

创建多元索引时,需要指定数据表名称(tableName)、多元索引名称(indexName)和索引的结构信息(indexSchema),其中indexSchema包含fieldSchemas(Index所有字段的设置)、indexSetting(索引设置)和indexSort(索引预排序设置)。详细参数说明请参见下表。

参数

说明

tableName

数据表名称。

indexName

多元索引名称。

fieldSchemas

索引字段列表,每个fieldSchema包含如下内容:

  • fieldName(必选):创建多元索引的字段名,即列名,类型为String。

    多元索引中的字段可以是主键列或者属性列。

  • fieldType(必选):字段类型,类型为FieldType.XXX。更多信息,请参见基础数据类型及映射

  • isArray(可选):是否为数组,类型为Boolean。

    如果设置为true,则表示该列是一个数组,在写入时,必须按照JSON数组格式写入,例如["a","b","c"]。

    由于Nested类型是一个数组,当fieldTypeNested类型时,无需设置此参数。

  • analyzer(可选):分词器类型。当字段类型为Text时,可以设置此参数;如果不设置此参数,则默认分词器类型为单字分词。关于分词的更多信息,请参见分词

  • isVirtualField(可选):该字段是否为虚拟列,类型为Boolean。默认值为false,表示字段不是虚拟列。如果要使用虚拟列,请设置此参数为true。关于虚拟列的更多信息,请参见虚拟列

  • sourceFieldName(可选):数据表中的字段名称,类型为String。当设置isVirtualFieldtrue时,必须设置此参数。

  • dateFormats(可选):日期的格式,类型为String。当字段类型为Date时,必须设置此参数。更多信息,请参见日期时间类型

  • enableHighlighting(可选):是否开启查询高亮功能,类型为Boolean。默认值为false,表示不开启查询高亮。如果要使用查询高亮,请设置此参数为true。仅Text类型字段支持查询高亮功能。关于查询高亮的更多信息,请参见查询高亮

    重要

    目前此参数只支持通过表格存储SDK进行配置。

  • enableSortAndAgg(可选):是否开启排序与统计聚合功能,类型为Boolean。默认值为true,表示开启排序与统计聚合。

    只有enableSortAndAgg设置为true的字段才能进行排序。关于排序的更多信息,请参见排序和翻页

    重要
    • 目前此参数只支持通过表格存储SDK进行配置。

    • TEXT类型的字段不支持排序和统计聚合。如果Text类型的字段同时需要进行排序或统计聚合,可以通过虚拟列为Keyword类型实现。具体操作,请参见虚拟列

  • vectorOptions(可选):向量字段类型的属性参数。当字段类型为Vector时,必须设置此参数。包括如下内容:

    • dataType:向量数据类型。当前仅支持float32。如果有其他类型需求,请提交工单联系我们。

    • dimension:向量维度。关于维度限制说明请参见多元索引限制

    • metricType:向量之间距离度量的算法,支持欧氏距离(euclidean)、余弦相似度(cosine)、点积(dot_product)。

      • 欧氏距离(euclidean):多维空间中两个向量之间的直线距离。出于性能考虑,表格存储中的欧氏距离算法未进行最后的平方根计算。欧氏距离的评分越大表示两个向量的相似度越大。

      • 余弦相似度(cosine):向量空间中两个向量间夹角的余弦值。余弦相似度的评分越高表示两个向量的相似度越大。常用于文本数据的相似度计算。

      • 点积(dot_product):维度相同的两个向量的对应坐标相乘,然后将结果相加。点积的评分越高标识两个向量的相似度越大。

      关于如何选用距离度量算法的更多信息,请参见附录:距离度量算法说明

indexSetting

索引设置,包含routingFields设置。

routingFields(可选):自定义路由字段。可以选择部分主键列作为路由字段,在进行索引数据写入时,会根据路由字段的值计算索引数据的分布位置,路由字段的值相同的记录会被索引到相同的数据分区中。

indexSort

索引预排序设置,包含sorters设置。如果不设置,则默认按照主键排序。

说明

含有Nested类型的索引不支持indexSort,没有预排序。

sorters(可选):索引预排序方式的列表,支持按照主键排序和字段值排序。更多信息,请参见排序和翻页

timeToLive

可选参数。数据生命周期(TTL),即数据的保存时间,单位为秒。

默认值为-1,表示数据永不过期。数据生命周期的取值最低为86400秒(一天),也可设置为-1(永不过期)。

当数据的保存时间超过设置的数据生命周期时,系统会自动清理超过数据生命周期的数据。

多元索引生命周期的使用方式,请参见生命周期管理

注意事项

  • 当要实现全文检索时,您可以在多元索引中将字段设置为可分词字符串(TEXT)类型并为TEXT类型的字段设置分词,然后使用匹配查询短语匹配查询功能查询数据。关于分词的更多信息,请参见分词

  • 在不修改表格存储的存储结构及数据的情况下,当要实现新字段和新数据类型的查询功能时,您可以在多元索引中将字段设置为虚拟列。更多信息,请参见虚拟列

  • 当要使用日期数据类型进行数据查询时,您可以在多元索引中将数据表中的整型(Integer)或字符串(String)类型的数据映射为日期数据类型。更多信息,请参见日期时间类型

  • 当要使用数值向量进行近似最近邻查询时,您可以在多元索引中将字段设置为向量类型,然后使用向量检索介绍与使用功能查询数据。

  • 当要使用数组类型存储数据时,您可以在数据表中以String类型字段存储数据,然后在多元索引中将字段设置为数组。

    在写入数据到数据表中时,数组类型字段的值必须按照JSON数组格式写入,例如["a","b","c"]。

    说明

    数组类型仅是多元索引中的概念,数据表中还不支持数组。更多信息,请参见数组和嵌套类型

  • 当要使用单字段存储存在层次关系或者一对多关系的数据时,您可以在多元索引中将字段设置为嵌套类型,然后使用嵌套类型查询功能查询数据。

    在写入数据到数据表中时,嵌套类型字段的值必须按照JSON数组格式写入,例如[{"tagName":"tag1", "score":0.8}, {"tagName":"tag2", "score":0.2}]

  • 当要存储的数据为地理位置信息时,您可以在多元索引中将字段设置为地理位置(Geo-point)类型,然后使用地理距离查询地理长方形范围查询地理多边形范围查询功能查询数据。

  • 系统默认使用分区键作为路由键,当要使用其他主键列作为路由键来定向搜索指定数据分区,以减少长尾对延迟的影响时,您可以修改路由字段配置。更多信息,请参见多元索引路由字段的使用

  • 多元索引默认按照主键升序的排序方式返回查询结果,当要按照指定字段值或主键降序进行预排序时,您可以修改预排序方式。更多信息,请参见索引预排序

  • 当要实现自动清理多元索引中的历史数据时,您可以使用多元索引的数据生命周期(TTL)功能有效地管理数据,减少数据存储空间,降低存储成本。更多信息,请参见生命周期管理

  • 当要在查询结果中高亮突出显示匹配到的关键词时,您可以使用查询高亮功能实现。更多信息,请参见查询高亮

使用方式

您可以使用控制台、命令行工具或者SDK进行创建多元索引操作。

进行多元索引创建之前,您需要完成如下准备工作。

  • 使用阿里云账号或者具有表格存储操作权限的RAM用户进行操作。如果需要为RAM用户授权表格存储操作权限,请参见通过RAM PolicyRAM用户授权进行配置。

    使用SDK方式和命令行工具方式进行操作时,如果当前无可用AccessKey,则需要为阿里云账号或者RAM用户创建AccessKey。具体操作,请参见创建AccessKey

  • 已创建数据表。具体操作,请参见数据表操作

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

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

使用控制台

通过控制台创建一个多元索引。

  1. 进入索引管理页签。

    1. 登录表格存储控制台

    2. 在页面上方,选择资源组和地域。

    3. 概览页面,单击实例名称或在操作列单击实例管理

    4. 实例详情页签的数据表列表区域,单击数据表名称或在操作列单击索引管理

  2. 索引管理页签,单击创建多元索引

  3. 创建索引对话框,创建多元索引。

    image.png

    1. 系统默认会自动生成索引名,可根据需要设置索引名。

    2. 选择Schema生成方式。

      重要

      字段名字段类型需与数据表匹配。数据表字段类型与多元索引字段类型的对应关系请参见基础数据类型及映射

      • 当设置Schema生成方式手动录入时,手动输入字段名,选择字段类型以及设置是否开启数组。

      • 当设置Schema生成方式自动生成时,系统会自动将数据表的主键列和属性列作为索引字段,可根据需要选择字段类型以及设置是否开启数组。

      说明

      在部分情况下如果要优化性能,则可以使用虚拟列。关于虚拟列的更多信息,请参见虚拟列

    3. 如果需要配置数据生命周期、路由键、索引预排序等选项,请打开高级选项开关,并根据下表说明配置参数。

      参数

      说明

      路由键

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

      数据生命周期

      多元索引中数据的保存时间,单位为秒。默认值为-1,表示数据永不过期。

      数据生命周期的取值最低为86400秒(一天),也可设置为-1(永不过期)。同时多元索引的TTL值必须小于或等于数据表的TTL值。

      如果需要系统自动清理多元索引中的历史数据,您可以配置数据生命周期为指定时间。当数据的保存时间超过设置的数据生命周期时,系统会自动清理超过数据生命周期的数据。

      预排序

      多元索引默认按照设置的索引预排序方式进行排序,用于确定数据的默认返回顺序。

      索引预排序只支持按照主键排序和按照字段值排序两种方式。如果未自定义预排序,则默认为主键排序,您可以根据实际查询场景指定预排序方式。

      重要

      含有Nested类型字段的多元索引不支持索引预排序。

  4. 单击确定

    多元索引创建完成后,在索引列表的操作列,单击索引详情,可查看索引表的索引基本信息、索引计量、路由键、索引字段和预排序等信息。

使用命令行工具

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

  1. 执行create_search_index命令创建一个多元索引search_index。

    create_search_index -n search_index
  2. 根据系统提示输入索引Schema,示例如下:

    索引Schema包括IndexSetting(索引设置)、FieldSchemas(Index的所有字段的设置)和IndexSort(索引预排序设置)。关于索引Schema的更多信息,请参见创建多元索引

     {
    
        "IndexSetting": {
            "RoutingFields": null
        },
        "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"
                ]
            }
        ]
    }

使用SDK

您可以通过Java SDKGo SDKPython SDKNode.js SDK.NET SDKPHP SDK创建多元索引。此处以Java SDK为例介绍创建多元索引的操作。

创建多元索引时使用默认配置

以下示例用于创建一个多元索引。该多元索引包含Col_Keyword(KEYWORD类型)、Col_Long(LONG类型)和Col_Vector(VECTOR类型)三列,按照数据表主键进行预排序且数据永不过期。

private static void createSearchIndex(SyncClient client) {
    CreateSearchIndexRequest request = new CreateSearchIndexRequest();
    //设置数据表名称。
    request.setTableName("<TABLE_NAME>"); 
    //设置多元索引名称。
    request.setIndexName("<SEARCH_INDEX_NAME>"); 
    IndexSchema indexSchema = new IndexSchema();
    indexSchema.setFieldSchemas(Arrays.asList(
            //设置字段名和类型。
            new FieldSchema("Col_Keyword", FieldType.KEYWORD), 
            new FieldSchema("Col_Long", FieldType.LONG),
            // 设置向量类型。
            new FieldSchema("Col_Vector", FieldType.VECTOR).setIndex(true)
                    // 向量维度为4,相似度算法为点积。
                    .setVectorOptions(new VectorOptions(VectorDataType.FLOAT_32, 4, VectorMetricType.DOT_PRODUCT))
    ));
    request.setIndexSchema(indexSchema);
    //调用client创建多元索引。
    client.createSearchIndex(request); 
}

创建多元索引时指定IndexSort

以下示例用于创建一个多元索引,多元索引包含Col_Keyword(KEYWORD类型)、Col_Long(LONG类型)、Col_Text(TEXT类型)和Timestamp(LONG类型)四列,同时配置按照Timestamp列进行预排序。

private static void createSearchIndexWithIndexSort(SyncClient client) {
    CreateSearchIndexRequest request = new CreateSearchIndexRequest();
    //设置数据表名称。
    request.setTableName("<TABLE_NAME>"); 
    //设置多元索引名称。
    request.setIndexName("<SEARCH_INDEX_NAME>"); 
    IndexSchema indexSchema = new IndexSchema();
    indexSchema.setFieldSchemas(Arrays.asList(
            new FieldSchema("Col_Keyword", FieldType.KEYWORD),
            new FieldSchema("Col_Long", FieldType.LONG),
            new FieldSchema("Col_Text", FieldType.TEXT),
            new FieldSchema("Timestamp", FieldType.LONG)
                    .setEnableSortAndAgg(true)));
    //设置按照Timestamp列进行预排序。
    indexSchema.setIndexSort(new Sort(
            Arrays.<Sort.Sorter>asList(new FieldSort("Timestamp", SortOrder.ASC))));
    request.setIndexSchema(indexSchema);
    //调用client创建多元索引。
    client.createSearchIndex(request);
}

创建多元索引时设置生命周期

重要

请确保数据表的更新状态为禁止。

以下示例用于创建一个多元索引,多元索引包含Col_Keyword(KEYWORD类型)和Col_Long(LONG类型)两列,同时指定多元索引生命周期为7天。

// 请使用5.12.0及以上版本的Java SDK。
public static void createIndexWithTTL(SyncClient client) {
    int days = 7;
    CreateSearchIndexRequest request = new CreateSearchIndexRequest();
    //设置数据表名称。
    request.setTableName("<TABLE_NAME>");
    //设置多元索引名称。
    request.setIndexName("<SEARCH_INDEX_NAME>");
    IndexSchema indexSchema = new IndexSchema();
    indexSchema.setFieldSchemas(Arrays.asList(
            //设置字段名和类型。
            new FieldSchema("Col_Keyword", FieldType.KEYWORD), 
            new FieldSchema("Col_Long", FieldType.LONG)));
    request.setIndexSchema(indexSchema);
    //设置多元索引TTL。
    request.setTimeToLiveInDays(days);
    //调用client创建多元索引。
    client.createSearchIndex(request);
}

创建多元索引时指定虚拟列

以下示例用于创建一个多元索引,多元索引包含Col_Keyword(KEYWORD类型)和Col_Long(LONG类型)两列,同时创建虚拟列Col_Keyword_Virtual_Long(LONG类型)和Col_Long_Virtual_Keyword(KEYWORD类型)。Col_Keyword_Virtual_Long映射为数据表中Col_Keyword列,虚拟列Col_Long_Virtual_Keyword映射为数据表中Col_Long列。

private static void createSearchIndex(SyncClient client) {
    CreateSearchIndexRequest request = new CreateSearchIndexRequest();
    //设置数据表名称。
    request.setTableName("<TABLE_NAME>"); 
    //设置多元索引名称。
    request.setIndexName("<SEARCH_INDEX_NAME>"); 
    IndexSchema indexSchema = new IndexSchema();
    indexSchema.setFieldSchemas(Arrays.asList(
        //设置字段名和类型。
        new FieldSchema("Col_Keyword", FieldType.KEYWORD), 
        //设置字段名和类型。
        new FieldSchema("Col_Keyword_Virtual_Long", FieldType.LONG) 
             //设置字段是否为虚拟列。
            .setVirtualField(true) 
             //虚拟列对应的数据表中字段。
            .setSourceFieldName("Col_Keyword"), 
        new FieldSchema("Col_Long", FieldType.LONG),
        new FieldSchema("Col_Long_Virtual_Keyword", FieldType.KEYWORD)
            .setVirtualField(true)
            .setSourceFieldName("Col_Long")));
    request.setIndexSchema(indexSchema);
    //调用client创建多元索引。
    client.createSearchIndex(request); 
}

创建多元索引时开启查询高亮

以下示例用于创建一个多元索引,多元索引包含Col_Keyword(KEYWORD类型)、Col_Long(LONG类型)和Col_Text(TEXT类型)三列,同时为Col_Text列开启查询高亮功能。

private static void createSearchIndexwithHighlighting(SyncClient client) {
    CreateSearchIndexRequest request = new CreateSearchIndexRequest();
    //设置数据表名称。
    request.setTableName("<TABLE_NAME>"); 
    //设置多元索引名称。
    request.setIndexName("<SEARCH_INDEX_NAME>"); 
    IndexSchema indexSchema = new IndexSchema();
    indexSchema.setFieldSchemas(Arrays.asList(
            //设置字段名和类型。
            new FieldSchema("Col_Keyword", FieldType.KEYWORD), 
            new FieldSchema("Col_Long", FieldType.LONG),
            //为字段开启查询高亮功能。
            new FieldSchema("Col_Text", FieldType.TEXT).setIndex(true).setEnableHighlighting(true)
    ));
    request.setIndexSchema(indexSchema);
    //调用client创建多元索引。
    client.createSearchIndex(request); 
}

后续操作

创建多元索引后,您可以通过多元索引进行数据查询、数据分析与数据导出。

操作

可选功能

数据查询

请根据实际业务场景选择合适的查询方式。

当通过Search接口查询数据时,如果要对结果集进行排序或者翻页,您可以使用排序和翻页功能来实现。具体操作,请参见排序和翻页

数据分析

统计聚合

数据导出

并发导出数据

相关文档

创建多元索引后,请根据需要执行相应操作。

  • 如果希望清理多元索引中的历史数据或者希望延长数据保存时间,您可以修改多元索引的数据生命周期。具体操作,请参见生命周期管理

  • 如果要在多元索引中新增、更新或者删除索引列,您可以使用动态修改schema功能实现。具体操作,请参见动态修改schema

  • 如果要获取某个数据表关联的所有多元索引的列表信息,您可以使用列出多元索引列表功能实现。具体操作,请参见列出多元索引列表

  • 如果要查询多元索引的描述信息,包括多元索引的字段信息和索引配置等,您可以使用查询多元索引描述信息功能实现。具体操作,请参见查询多元索引描述信息

  • 如果不再需要使用多元索引,您可以删除多元索引。具体操作,请参见删除多元索引

  • 您还可以使用SQL查询功能或者通过MaxCompute、Spark、Hive或者HadoopMR、函数计算、Flink、PrestoDB等计算引擎计算与分析表中数据。具体操作,请参见SQL查询计算与分析概述

附录:距离度量算法说明

向量的距离度量算法说明请参见下表,其中评分公式的值越大表示的相似度越大。

MetricType

评分公式

性能

说明

欧氏距离

(euclidean)

较高

多维空间中两个向量之间的直线距离。出于性能考虑,表格存储中的欧氏距离算法未进行最后的平方根计算。欧氏距离的评分越大表示两个向量的相似度越大。

点积

(dot_product)

最高

维度相同的两个向量的对应坐标相乘,然后将结果相加。点积的评分越高表示两个向量的相似度越大。

Float32向量必须在写入表前进行归一化(例如使用L2范数进行归一化),否则会出现查询效果差、构建向量索引慢、查询性能差等潜在问题。

余弦相似度

(cosine)

较低

向量空间中两个向量间夹角的余弦值。余弦相似度的评分越高表示两个向量的相似度越大。常用于文本数据的相似度计算。

由于0无法作为除数,无法完成余弦相似度的计算,因此Float32向量的平方和不允许为0

余弦相似度计算复杂,推荐您在写入数据到表之前进行向量的归一化,然后使用点积(dot_product)作为向量距离的度量算法。

向量归一化的示例代码如下:

  public static float[] l2normalize(float[] v, boolean throwOnZero) {
    double squareSum = 0.0f;
    int dim = v.length;
    for (float x : v) {
      squareSum += x * x;
    }
    if (squareSum == 0) {
      if (throwOnZero) {
        throw new IllegalArgumentException("can't normalize a zero-length vector");
      } else {
        return v;
      }
    }
    double length = Math.sqrt(squareSum);
    for (int i = 0; i < dim; i++) {
      v[i] /= length;
    }
    return v;
  }