Os índices de busca aceitam o tipo de campo JSON. Mapeie uma coluna String de uma tabela de dados para um campo JSON em um índice de busca e execute buscas estruturadas e análises em dados semiestruturados. O tipo de campo JSON oferece dois modos de armazenamento: Object e Nested, adequados respectivamente para consultas a campos independentes e consultas correlacionadas de objetos aninhados.
Funcionamento
Ao mapear uma coluna String para um campo JSON em um índice de busca, o Tablestore analisa a estrutura JSON e indexa subcampos individuais para consulta. Dois modos de armazenamento estão disponíveis — Object e Nested — cada um otimizado para diferentes padrões de consulta.
Object: Achata estruturas aninhadas em campos de nível superior. Ideal para consultas simples a campos que exigem alto desempenho.
Nested: Preserva a independência e as associações de campos de cada objeto aninhado. Recomendado para consultas que exigem correspondência exata dentro de um único objeto aninhado.
Principais diferenças
|
Dimensão |
Object |
Nested |
|
Processamento de dados |
Achata dados aninhados em campos de nível superior |
Armazena cada objeto aninhado como um documento independente |
|
Método de consulta |
Consultas padrão |
Requer NestedQuery |
|
Correlação de campos |
Permite correspondência cruzada entre campos de diferentes objetos aninhados |
Corresponde a campos apenas dentro do mesmo objeto aninhado |
|
Desempenho |
Menor consumo de recursos |
Maior consumo de recursos; aceita consultas a campos correlacionados |
Diretrizes de seleção
Escolha Nested quando as consultas precisarem preservar estritamente as correlações de campos dentro dos objetos aninhados. Opte por Object quando a prioridade for o alto desempenho de consulta e a correlação estrita de campos não for necessária.
Configurar e usar índices de campos JSON
Crie um índice de busca para campos JSON em três etapas: selecione um tipo JSON, configure o índice e execute consultas.
Independentemente da escolha entre Object ou Nested, defina explicitamente o tipo de cada subcampo. O índice ignora subcampos sem tipo definido, impedindo sua participação em consultas.
Etapa 1: Selecione o tipo JSON e o formato de dados
As seções a seguir comparam os tipos Object e Nested, mostram os formatos de dados compatíveis e demonstram como gravar dados JSON.
Seleção do tipo JSON
Object: Mais indicado para consultas a campos independentes. Oferece alto desempenho de consulta com baixo consumo de recursos.
Nested: Projetado para cenários de consulta que exigem correlação de campos. Garante resultados precisos dentro de cada objeto aninhado.
Híbrido: Combine os tipos Object e Nested no mesmo índice para atender a requisitos complexos.
Formato de dados
Campos JSON aceitam formatos de array e não-array. Escolha o formato com base na sua estrutura de dados:
// Array format
[{ "country": "China", "city": "Hangzhou" }, { "country": "USA", "city": "Seattle" }]
// Non-array format
{ "country": "China", "city": "Hangzhou" }
Gravar dados
private static void putRow(SyncClient client) {
// Construct the primary key.
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
primaryKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("10001"));
PrimaryKey primaryKey = primaryKeyBuilder.build();
// Specify the table name.
RowPutChange rowPutChange = new RowPutChange("<TABLE_NAME>", primaryKey);
// Build the raw JSON data.
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));
}
Etapa 2: Configure a estrutura de campos e crie um índice
O exemplo a seguir configura um campo JSON de nível único com dois subcampos. Defina o tipo e as propriedades de cada subcampo para torná-los consultáveis.
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) // Set to JsonType.OBJECT or JsonType.NESTED
.setSubFieldSchemas(subFieldSchemas);
Etapa 3: Consulte dados
Object: Achata dados aninhados. Acesse os campos concatenando os nomes dos campos pai e filho com um ponto (
.). Como os campos são achatados, valores de diferentes objetos aninhados podem ter correspondência cruzada.Nested: Preserva a independência de cada objeto aninhado. Envolva as condições de consulta em um NestedQuery para garantir que a correspondência de campos ocorra apenas dentro do mesmo objeto aninhado.
Formato indexado
Considere que o campo address contenha os seguintes dados: [{ "country": "China", "city": "Hangzhou" }, { "country": "USA", "city": "Seattle" }].
Formato indexado Object:
{"address.country": ["China", "USA"], "address.city": ["Hangzhou","Seattle"]}Formato indexado Nested: Documentos independentes
{ "country": "China", "city": "Hangzhou" }e{ "country": "USA", "city": "Seattle" }
Com as condições address.country ="China" E address.city="Seattle", o tipo Object encontra correspondência (valores de campos entre objetos se combinam), mas o Nested não (nenhum objeto único possui ambos). Já com as condições address.country ="China" E address.city="Hangzhou", ambos os tipos encontram correspondência.
Exemplos de consulta
Exemplo de consulta do tipo JSON Nested
O exemplo a seguir consulta linhas em que o mesmo objeto aninhado do campo address satisfaz duas condições: address.country é "China" e address.city é "Seattle".
public static void nestedQuery(SyncClient client) {
// Condition 1: The value of the country field in the address sub-row must be "China".
TermQuery termQuery1 = new TermQuery();
termQuery1.setFieldName("address.country");
termQuery1.setTerm(ColumnValue.fromString("China"));
// Condition 2: The value of the city field in the address sub-row must be "Seattle".
TermQuery termQuery2 = new TermQuery();
termQuery2.setFieldName("address.city");
termQuery2.setTerm(ColumnValue.fromString("Seattle"));
// Use the AND condition of BoolQuery to query for sub-rows that meet both conditions.
List<Query> mustQueries = new ArrayList<>();
mustQueries.add(termQuery1);
mustQueries.add(termQuery2);
BoolQuery boolQuery = new BoolQuery();
boolQuery.setMustQueries(mustQueries);
// Set BoolQuery within NestedQuery to require a sub-row to meet multiple query conditions at the same time.
NestedQuery nestedQuery = new NestedQuery(); // Set the query type to NestedQuery.
nestedQuery.setPath("address"); // Set the path of the nested type column, which is the parent path of the field to query.
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());
}
Exemplo de consulta do tipo JSON Object
O exemplo a seguir consulta linhas em que o campo address satisfaz duas condições em seus objetos aninhados: address.country é "China" e address.city é "Seattle".
public static void boolQuery(SyncClient client) {
// Condition 1: The value of the country field in the address sub-row must be "China".
TermQuery termQuery1 = new TermQuery();
termQuery1.setFieldName("address.country");
termQuery1.setTerm(ColumnValue.fromString("China"));
// Condition 2: The value of the city field in the address sub-row must be "Seattle".
TermQuery termQuery2 = new TermQuery();
termQuery2.setFieldName("address.city");
termQuery2.setTerm(ColumnValue.fromString("Seattle"));
// Use the AND condition of BoolQuery to query for sub-rows that meet both conditions.
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());
}
Exemplos de JSON
A configuração de esquema para campos JSON de nível único e multinível segue a mesma estrutura tanto para Object quanto para Nested. Apenas a definição de tipo difere.
JSON de nível único
O exemplo Java a seguir cria um campo JSON de nível único tags (selecione o tipo JSON conforme seus requisitos) com três subcampos:
tagName: Tipo Keyword. Usado para correspondência exata e agregação de nomes de tags.
score: Tipo Double. Usado para cálculos numéricos e ordenação de pesos de tags.
time: Tipo Date no formato epoch_millis. Usado para consultas de intervalo de tempo e análise de séries temporais.
Tanto formatos de array quanto de não-array são aceitos para gravação de dados:
// Array format
[{"tagName":"tag1", "score":0.8,"time": 1730690237000 }, {"tagName":"tag2", "score":0.2,"time": 1730691557000}]
// Non-array format
{"tagName":"tag1", "score":0.8,"time": 1730690237000 }
Configuração completa do esquema:
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) // Replace with JsonType.NESTED as needed
.setSubFieldSchemas(subFieldSchemas);
JSON multinível
O exemplo Java a seguir cria um campo JSON multinível user (selecione o tipo JSON conforme seus requisitos) com informações básicas do usuário e dados de endereço aninhados. Campos JSON multiníveis aceitam uma mistura de tipos Nested e Object.
Campos básicos: name (Keyword, para consultas exatas de nome), age (Long, para filtragem por faixa etária), birth (Date, formato yyyy-MM-dd HH:mm:ss.SSS, para consultas de aniversário), phone (Keyword, para correspondência de contato).
Campo aninhado:
address(selecione o tipo JSON conforme seus requisitos), contendoprovince,cityestreet(todos do tipo Keyword) para consultas hierárquicas de localização.
Dados de usuário de exemplo:
{
"name": "John",
"age": 20,
"birth": "2014-10-10 12:00:00.000",
"phone": "1390000****",
"address": {
"province": "Zhejiang",
"city": "Hangzhou",
"street": "1201, Sunshine Community, Yangguang Avenue"
}
}
Configuração completa do esquema para JSON multinível:
// Sub-field schema for address (path: 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));
// Sub-field schema for user (path: 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) // Replace with JsonType.OBJECT as needed
.setSubFieldSchemas(addressSubFiledSchemas));
// Create the parent field: user
List<FieldSchema> fieldSchemas = new ArrayList<>();
fieldSchemas.add(new FieldSchema("user",FieldType.JSON)
.setJsonType(JsonType.OBJECT) // Replace with JsonType.NESTED as needed
.setSubFieldSchemas(subFieldSchemas));
Limitações
Campos vetoriais: Não use campos vetoriais como subcampos de um campo JSON. Configure índices de campos vetoriais independentemente.
Tipo Nested: Campos JSON Nested não aceitam pré-ordenação de índice. Use NestedQuery para consultar campos aninhados.
Subcampos de array: Para subcampos não-JSON com dados em formato de array, defina a propriedade IsArray como true. Grave dados no formato de array padrão
"[a, b, c]". Caso contrário, o índice não consegue sincronizar ou consultar o subcampo.
Referências
Atualmente, o tipo de campo JSON é compatível com o Tablestore SDK for Java, o Tablestore SDK for Go e o Tablestore SDK for Python.