多元索引支持JSON类型字段,通过高效存储和灵活查询半结构化数据,解决日志分析、用户行为记录、配置管理等复杂业务场景中嵌套数据结构的检索与分析需求,显著提升查询效率和数据处理准确性。
如需使用多元索引JSON类型,请联系表格存储技术支持开通。
工作原理
通过将数据表中的String类型字段映射到多元索引的JSON类型字段,支持具有层级结构的半结构化数据处理,针对不同业务查询需求和性能要求,提供Object类型和Nested类型两种JSON存储模式。
Object类型:采用扁平化存储策略,将嵌套结构转换为平级字段,适用于对查询性能要求较高的简单字段检索场景。
Nested类型:维持嵌套对象的独立性和字段关联关系,适用于需要精确匹配对象内字段组合的复杂查询场景。
核心区别
两种JSON类型在数据处理方式、查询语法、字段关联性和性能特点方面存在显著差异:
数据处理方式:Object类型将嵌套数据扁平化存储,Nested类型将每个嵌套对象作为独立文档存储。
查询方式:Object类型使用基础查询,Nested类型必须使用NestedQuery查询。
字段关联性:Object类型允许不同嵌套对象的字段交叉匹配,Nested类型确保每个嵌套对象内的字段独立匹配。
性能特点:Object类型查询轻量高效,资源消耗低,Nested类型功能强大但资源消耗相对较高。
选择原则
当业务查询需要严格保持嵌套对象内字段的关联性和准确性时,选择Nested类型;当追求高查询性能且对字段关联性要求不严格时,优先选择Object类型。
配置和使用JSON类型索引
通过完整的JSON类型字段索引配置流程,从类型选择、索引创建到查询验证,为半结构化数据建立高效可靠的检索体系。
无论JSON类型选择Object还是Nested,都必须为所有子字段明确定义字段类型,未定义类型的字段将被索引系统忽略,无法参与查询。
步骤一:选择JSON类型和数据格式
根据具体的业务查询需求、性能要求和数据结构特点,选择最适合的JSON类型和数据写入格式。
JSON类型选择策略
Object类型:适用于简单字段独立查询,提供优异的查询性能和较低的资源消耗。
Nested类型:适用于需要维护字段关联性的精确查询,确保查询结果的准确性。
混合使用:Object和Nested类型支持在同一索引中灵活组合,满足复杂业务场景需求。
数据写入格式规范
JSON字段支持数组格式和非数组格式两种数据写入方式,根据业务数据结构选择合适的格式:
//数组格式
[{ "country": "China", "city": "hangzhou" }, { "country": "usa", "city": "Seattle" }]
//非数组格式
{ "country": "China", "city": "hangzhou" }数据写入示例
private static void putRow(SyncClient client) {
//构造主键。
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("10001"));
PrimaryKey primaryKey = primaryKeyBuilder.build();
//设置数据表名称。
RowPutChange rowPutChange = new RowPutChange("<TABLE_NAME>", primaryKey);
// 构建JSON原始数据。
List<Map<String, Object>> addresses = Arrays.asList(
new HashMap<String, Object>() {{ put("country", "China"); put("city", "hangzhou"); }},
new HashMap<String, Object>() {{ put("country", "usa"); put("city", "Seattle"); }}
);
String jsonString = JSON.toJSONString(addresses);
rowPutChange.addColumn(new Column("address", ColumnValue.fromString(jsonString)));
client.putRow(new PutRowRequest(rowPutChange));
}步骤二:配置字段结构和创建索引
以包含两个子字段的单层级JSON为例,演示完整的索引配置实现过程。通过合理的字段类型定义和属性设置,确保索引功能的完整性和查询性能的优化。
List<FieldSchema> subFieldSchemas = new ArrayList<FieldSchema>();
subFieldSchemas.add(new FieldSchema("country", FieldType.KEYWORD)
.setIndex(true).setEnableSortAndAgg(true));
subFieldSchemas.add(new FieldSchema("city", FieldType.KEYWORD)
.setIndex(true).setEnableSortAndAgg(true));
FieldSchema jsonFieldSchema = new FieldSchema("address", FieldType.Json)
.setJsonType(JsonType.OBJECT) // 设置为JsonType.OBJECT或JsonType.NESTED
.setSubFieldSchemas(subFieldSchemas);步骤三:查询数据
通过实际的查询测试验证索引配置的正确性,对比Object和Nested两种JSON类型在相同数据和查询条件下的不同查询行为和结果差异。
Object类型:将嵌套数据扁平化处理,查询时使用父子字段名通过半角句号连接的路径访问方式。扁平化存储使得不同嵌套对象的字段值可以交叉匹配。
Nested类型:保持每个嵌套对象的独立性和完整性,必须使用NestedQuery包装查询条件,确保字段匹配仅在同一嵌套对象内进行。
索引后格式
假设示例数据为address字段的数据为 [{ "country": "China", "city": "hangzhou" }, { "country": "usa", "city": "Seattle" }]。
Object类型的JSON索引后格式:
{"address.country": ["China", "usa"], "address.city": ["hangzhou","Seattle"]}Nested类型的JSON索引后格式:独立文档
{ "country": "China", "city": "hangzhou" }和{ "country": "usa", "city": "Seattle" }
由上可知,当查询条件为address.country ="China"且address.city="Seattle"时,Object类型的JSON会匹配到数据,Nested类型的JSON无法匹配到数据;当查询条件为address.country ="China"且address.city="hangzhou"时,Object类型或Nested类型的JSON均会匹配到数据。
查询示例
JSON Nested类型查询示例
以下示例用于查询address的同一子行能满足address.country为"China"且address.city为"Seattle"两个条件的行数据。
public static void nestedQuery(SyncClient client) {
// 查询条件一:要求address子行的country列值为"China"
TermQuery termQuery1 = new TermQuery();
termQuery1.setFieldName("address.country");
termQuery1.setTerm(ColumnValue.fromString("China"));
// 查询条件二:要求address子行的city列值为"Seattle"
TermQuery termQuery2 = new TermQuery();
termQuery2.setFieldName("address.city");
termQuery2.setTerm(ColumnValue.fromString("Seattle"));
// 通过BoolQuery的And条件,查询同时满足上述条件的子行
List<Query> mustQueries = new ArrayList<>();
mustQueries.add(termQuery1);
mustQueries.add(termQuery2);
BoolQuery boolQuery = new BoolQuery();
boolQuery.setMustQueries(mustQueries);
// NestedQuery内部设置BoolQuery,要求某一子行同时满足多个查询条件
NestedQuery nestedQuery = new NestedQuery(); //设置查询类型为NestedQuery。
nestedQuery.setPath("address"); //设置嵌套类型列的路径,即要查询字段的父路径。
nestedQuery.setQuery(boolQuery);
nestedQuery.setScoreMode(ScoreMode.None);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(nestedQuery);
SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);
SearchResponse resp = client.search(searchRequest);
System.out.println("Row: " + resp.getRows());
}JSON Object类型查询示例
以下示例用于查询address列的多个子行满足address.country为"China"且address.city为"Seattle"两个条件的行数据。
public static void boolQuery(SyncClient client) {
// 查询条件一:要求address子行的country列值为"China"
TermQuery termQuery1 = new TermQuery();
termQuery1.setFieldName("address.country");
termQuery1.setTerm(ColumnValue.fromString("China"));
// 查询条件二:要求address子行的city列值为"Seattle"
TermQuery termQuery2 = new TermQuery();
termQuery2.setFieldName("address.city");
termQuery2.setTerm(ColumnValue.fromString("Seattle"));
// 通过BoolQuery的And条件,查询同时满足上述条件的子行
List<Query> mustQueries = new ArrayList<>();
mustQueries.add(termQuery1);
mustQueries.add(termQuery2);
BoolQuery boolQuery = new BoolQuery();
boolQuery.setMustQueries(mustQueries);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(boolQuery);
SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);
SearchResponse resp = client.search(searchRequest);
System.out.println("Row: " + resp.getRows());
}JSON类型应用示例
无论JSON类型选择Object还是Nested,单层级与多层级的Schema配置结构保持一致,仅在类型设置上有所区别,便于灵活切换和统一管理。
单层级JSON示例
以Java代码为例,创建单层级JSON字段tags(可根据需求选择JSON类型),包含以下三个功能字段:
tagName:字符串类型(Keyword),用于标签名称的精确匹配和聚合分析。
score:浮点数类型(Double),用于标签权重的数值计算和排序。
time:日期时间类型(Date),采用毫秒时间戳格式,用于时间范围查询和时序分析。
数据写入时支持数组和非数组两种格式,可根据业务数据结构灵活选择:
// 数组形式
[{"tagName":"tag1", "score":0.8,"time": 1730690237000 }, {"tagName":"tag2", "score":0.2,"time": 1730691557000}]
// 非数组形式
{"tagName":"tag1", "score":0.8,"time": 1730690237000 }完整的Schema配置代码实现:
List<FieldSchema> subFieldSchemas = new ArrayList<FieldSchema>();
subFieldSchemas.add(new FieldSchema("tagName", FieldType.KEYWORD)
.setIndex(true).setEnableSortAndAgg(true));
subFieldSchemas.add(new FieldSchema("score", FieldType.DOUBLE)
.setIndex(true).setEnableSortAndAgg(true));
subFieldSchemas.add(new FieldSchema("time", FieldType.DATE)
.setDateFormats(Arrays.asList("epoch_millis")));
FieldSchema nestedFieldSchema = new FieldSchema("tags", FieldType.Json)
.setJsonType(JsonType.OBJECT) // 按需替换为JsonType.NESTED
.setSubFieldSchemas(subFieldSchemas);多层级JSON示例
以Java代码为例,创建多层级JSON字段user(可根据需求设置JsonType),构建包含基础用户信息和嵌套地址信息的完整数据结构。使用多层级JSON时支持混合使用Nested类型和Object类型。
基础字段:name(Keyword类型,用于姓名精确查询)、age(Long类型,用于年龄范围筛选)、birth(Date类型,格式为yyyy-MM-dd HH:mm:ss.SSS,用于生日时间查询)、phone(Keyword类型,用于联系方式匹配)。
嵌套字段:
address(可根据需求设置JsonType),包含province、city、street三个地址层级字段(均为Keyword类型),支持地理位置的层级查询。
典型的用户数据写入示例:
{
"name": "张三",
"age": 20,
"birth": "2014-10-10 12:00:00.000",
"phone": "1390000****",
"address": {
"province": "浙江省",
"city": "杭州市",
"street": "阳光大道幸福小区1201号"
}
}
多层级JSON的完整Schema配置实现:
// address子字段Schema(路径:user.address)
List<FieldSchema> addressSubFiledSchemas = new ArrayList<>();
addressSubFiledSchemas.add(new FieldSchema("province",FieldType.KEYWORD));
addressSubFiledSchemas.add(new FieldSchema("city",FieldType.KEYWORD));
addressSubFiledSchemas.add(new FieldSchema("street",FieldType.KEYWORD));
// user子字段Schema(路径:user)
List<FieldSchema> subFieldSchemas = new ArrayList<>();
subFieldSchemas.add(new FieldSchema("name",FieldType.KEYWORD));
subFieldSchemas.add(new FieldSchema("age",FieldType.LONG));
subFieldSchemas.add(new FieldSchema("birth",FieldType.DATE)
.setDateFormats(Arrays.asList("yyyy-MM-dd HH:mm:ss.SSS")));
subFieldSchemas.add(new FieldSchema("phone",FieldType.KEYWORD));
subFieldSchemas.add(new FieldSchema("address",FieldType.JSON)
.setJsonType(JsonType.NESTED) // 按需替换为JsonType.OBJECT
.setSubFieldSchemas(addressSubFiledSchemas));
// 创建父字段user
List<FieldSchema> fieldSchemas = new ArrayList<>();
fieldSchemas.add(new FieldSchema("user",FieldType.JSON)
.setJsonType(JsonType.OBJECT) // 按需替换为JsonType.NESTED
.setSubFieldSchemas(subFieldSchemas));配额与限制
JSON类型字段在使用过程中存在以下功能限制和配置要求,需在索引设计时予以考虑:
向量类型限制:向量类型字段无法作为JSON字段的子字段使用,需独立配置向量字段索引。
Nested类型限制:当JSON字段类型设置为Nested时,该字段无法使用索引预排序功能,查询时必须使用NestedQuery进行查询。
子字段数组配置要求:当非JSON类型的子字段采用数组格式写入数据时,必须在字段配置中将IsArray属性设置为true,同时确保数据写入格式为
`"[a, b, c]"`的标准数组格式,否则该子字段的数据无法被索引正确同步和检索。
开发集成
目前支持通过Java SDK、Go SDK和Python SDK使用JSON类型。