Los índices de búsqueda admiten el tipo de campo JSON. Asigne una columna String de una tabla de datos a un campo JSON en un índice de búsqueda para ejecutar búsquedas estructuradas y análisis sobre datos semiestructurados. El tipo de campo JSON ofrece dos modos de almacenamiento: Object y Nested. El primero es adecuado para consultas de campos independientes, mientras que el segundo se recomienda para consultas de objetos anidados correlacionados.
Funcionamiento
Cuando asigna una columna String a un campo JSON en un índice de búsqueda, Tablestore analiza la estructura JSON e indexa cada subcampo individualmente para las consultas. Existen dos modos de almacenamiento disponibles: Object y Nested. Cada uno está optimizado para distintos patrones de consulta.
Object: aplana las estructuras anidadas y las convierte en campos de nivel superior. Es ideal para consultas simples de campos que requieren alto rendimiento.
Nested: conserva la independencia y las asociaciones de campos de cada objeto anidado. Resulta más indicado cuando necesita coincidencias exactas dentro de un único objeto anidado.
Diferencias clave
|
Dimensión |
Object |
Nested |
|
Procesamiento de datos |
Aplana los datos anidados en campos de nivel superior |
Almacena cada objeto anidado como un documento independiente |
|
Método de consulta |
Consultas estándar |
Requiere NestedQuery |
|
Correlación de campos |
Permite coincidencias cruzadas entre campos de distintos objetos anidados |
Solo establece coincidencias de campos dentro del mismo objeto anidado |
|
Rendimiento |
Menor consumo de recursos |
Mayor consumo de recursos; admite consultas de campos correlacionados |
Criterios de selección
Elija Nested cuando sus consultas deban conservar estrictamente las correlaciones de campos dentro de los objetos anidados. Elija Object si la prioridad es obtener un alto rendimiento en las consultas y no requiere una correlación estricta de campos.
Configurar y usar índices de campos JSON
Para crear un índice de búsqueda para campos JSON, siga tres pasos: seleccione un tipo JSON, configure el índice y ejecute las consultas.
Sin importar si elige Object o Nested, defina explícitamente el tipo de campo para cada subcampo. El índice ignora los subcampos sin un tipo definido, por lo que no pueden participar en las consultas.
Paso 1: Seleccione el tipo JSON y el formato de datos
A continuación se comparan los tipos Object y Nested, se muestran los formatos de datos compatibles y se explica cómo escribir datos JSON.
Selección del tipo JSON
Object: diseñado para escenarios de consultas de campos independientes. Ofrece un alto rendimiento con bajo consumo de recursos.
Nested: recomendado cuando las consultas exigen correlación de campos. Garantiza resultados precisos dentro de cada objeto anidado.
Híbrido: puede combinar los tipos Object y Nested en un mismo índice para cubrir requisitos complejos.
Formato de datos
Los campos JSON admiten formatos de arreglo y de valor único. Seleccione el formato según su estructura de datos:
// Array format
[{ "country": "China", "city": "Hangzhou" }, { "country": "USA", "city": "Seattle" }]
// Non-array format
{ "country": "China", "city": "Hangzhou" }
Escribir datos
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));
}
Paso 2: Configure la estructura de campos y cree un índice
El siguiente ejemplo configura un campo JSON de un solo nivel con dos subcampos. Defina el tipo y las propiedades de cada subcampo para que puedan consultarse.
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);
Paso 3: Consulte los datos
Object: aplana los datos anidados. Acceda a los campos concatenando el nombre del campo padre y el del hijo con un punto (
.). Dado que los campos están aplanados, los valores de distintos objetos anidados pueden coincidir de forma cruzada.Nested: conserva la independencia de cada objeto anidado. Envuelva las condiciones de consulta en un NestedQuery para asegurar que la coincidencia de campos ocurra únicamente dentro del mismo objeto anidado.
Formato indexado
Suponga que el campo address contiene los siguientes datos: [{ "country": "China", "city": "Hangzhou" }, { "country": "USA", "city": "Seattle" }].
Formato indexado de Object:
{"address.country": ["China", "USA"], "address.city": ["Hangzhou","Seattle"]}Formato indexado de Nested: documentos independientes
{ "country": "China", "city": "Hangzhou" }y{ "country": "USA", "city": "Seattle" }
Si aplica las condiciones address.country ="China" AND address.city="Seattle", Object genera una coincidencia porque combina valores de campos de distintos objetos, pero Nested no, ya que ningún objeto individual tiene ambos valores. Con las condiciones address.country ="China" AND address.city="Hangzhou", ambos tipos generan coincidencia.
Ejemplos de consulta
Ejemplo de consulta con el tipo JSON Nested
El siguiente ejemplo consulta las filas donde un mismo objeto anidado del campo address cumple dos condiciones: address.country es "China" y address.city es "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());
}
Ejemplo de consulta con el tipo JSON Object
El siguiente ejemplo consulta las filas donde el campo address cumple dos condiciones entre sus objetos anidados: address.country es "China" y address.city es "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());
}
Ejemplos de JSON
La configuración de esquema para campos JSON de un solo nivel y multinivel sigue la misma estructura tanto para Object como para Nested. La única diferencia radica en el ajuste del tipo.
JSON de un solo nivel
El siguiente ejemplo en Java crea un campo JSON de un solo nivel llamado tags (seleccione el tipo JSON según sus necesidades) con tres subcampos:
tagName: tipo Keyword. Se utiliza para coincidencias exactas y agregaciones de nombres de etiquetas.
score: tipo Double. Sirve para cálculos numéricos y ordenamiento de pesos de etiquetas.
time: tipo Date en formato epoch_millis. Apropiado para consultas de intervalos de tiempo y análisis de series temporales.
Para escribir datos, se admiten tanto el formato de arreglo como el de valor único:
// 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 }
Configuración completa del 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 multinivel
El siguiente ejemplo en Java crea un campo JSON multinivel llamado user (seleccione el tipo JSON según sus necesidades) con información básica del usuario y datos de dirección anidados. Los campos JSON multinivel admiten una combinación de los tipos Nested y Object.
Campos básicos: name (Keyword, para consultas exactas de nombre), age (Long, para filtrar por intervalo de edad), birth (Date, formato yyyy-MM-dd HH:mm:ss.SSS, para consultas de fecha de nacimiento) y phone (Keyword, para coincidencias de contacto).
Campo anidado:
address(seleccione el tipo JSON según sus necesidades), que contieneprovince,cityystreet(todos de tipo Keyword) para consultas jerárquicas de ubicación.
Datos de usuario de ejemplo:
{
"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"
}
}
Configuración completa del esquema para JSON multinivel:
// 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));
Límites
Campos vectoriales: los campos vectoriales no pueden usarse como subcampos de un campo JSON. Configure los índices de campos vectoriales de forma independiente.
Tipo Nested: los campos JSON anidados no admiten preordenamiento del índice. Utilice NestedQuery para consultar campos anidados.
Subcampos de arreglo: para los subcampos que no son JSON y contienen datos en formato de arreglo, establezca la propiedad IsArray en true. Escriba los datos en el formato de arreglo estándar
"[a, b, c]". De lo contrario, el índice no podrá sincronizar ni consultar el subcampo.
Referencias
Actualmente, el tipo de campo JSON es compatible con Tablestore SDK for Java, Tablestore SDK for Go y Tablestore SDK for Python.