En los escenarios de consulta de comodines (WildcardQuery) que usan el patrón *word*, puede combinar la tokenización difusa con una consulta de coincidencia de frases para ejecutar consultas difusas de alto rendimiento.
Contexto
Las consultas difusas son un requisito común en las operaciones de bases de datos, como buscar nombres de archivos o números de celular. Para ejecutar consultas difusas en Tablestore, utilice una consulta de comodines sobre un índice de búsqueda, lo cual es similar a la función LIKE de MySQL. Sin embargo, las consultas de comodines tienen limitaciones: la cadena de búsqueda no puede superar los 32 caracteres y el rendimiento disminuye conforme aumenta el volumen de datos.
Para resolver estos problemas, el índice de búsqueda admite consultas de comodines basadas en tokens, lo que mejora el rendimiento de las consultas difusas. Al usar este tipo de consulta, no existe límite en la longitud de la cadena de búsqueda. No obstante, el contenido original tiene un máximo de 1,024 caracteres. El contenido que supera este límite se trunca y solo se conservan los primeros 1,024 caracteres.
Escenarios
Elija el método adecuado para ejecutar consultas difusas según su escenario.
-
Si su escenario de consulta de comodines usa el patrón
*word*, utilice una consulta de comodines basada en tokens. Por ejemplo, busque"123"para encontrar números de celular que contengan123en cualquier posición.En la mayoría de los casos, este método mejora el rendimiento más de 10 veces en comparación con una consulta de comodines estándar.
Suponga que una tabla de datos contiene una columna file_name. En el índice de búsqueda, esta columna es de tipo Text y el analizador está configurado como Fuzzy Analyzer. Para encontrar la fila donde el valor de la columna file_name es
2021 woRK@Hangzhou, debe usar una consulta de coincidencia de frases (MatchPhraseQuery). La cadena de búsqueda debe ser una subcadena consecutiva del texto original.Si la cadena de búsqueda es
2021,20,21,work,WORK,@,Hang,zhou,Hangzhouo@Hangzhou, la consulta coincide con la fila cuyo valor en la columna file_name es2021 woRK@Hangzhou.Si la cadena de búsqueda es
21work,2021Hangzhou,2120o#Hangzhou, la consulta no coincide con la fila cuyo valor en la columna file_name es2021 woRK@Hangzhou.
Para otros escenarios de consulta complejos, utilice una consulta de comodines para ejecutar consultas difusas. Para obtener más información, consulte Wildcard query.
Uso
Siga estos pasos para ejecutar una consulta difusa mediante el método basado en tokens:
-
Cuando cree un índice de búsqueda, establezca el tipo de columna en Text y el analizador en Fuzzy Analyzer. Puede dejar los demás parámetros con sus valores predeterminados. Para obtener más información, consulte Create a search index.
NotaSi ya existe un índice de búsqueda, utilice la función de modificación dinámica de esquemas para agregar una columna virtual a la columna especificada. Establezca el tipo de la columna virtual en Text y el analizador en Fuzzy Analyzer. Para obtener más información, consulte Dynamically modify a schema y Virtual columns.
Cuando consulte datos mediante el índice de búsqueda, use MatchPhraseQuery. Para obtener más información, consulte Match phrase query.
Apéndice: caso de uso
A continuación se muestra cómo usar una consulta de comodines basada en tokens para ejecutar una consulta difusa.
import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.model.ColumnValue;
import com.alicloud.openservices.tablestore.model.PrimaryKey;
import com.alicloud.openservices.tablestore.model.PrimaryKeyBuilder;
import com.alicloud.openservices.tablestore.model.PrimaryKeyValue;
import com.alicloud.openservices.tablestore.model.PutRowRequest;
import com.alicloud.openservices.tablestore.model.RowPutChange;
import com.alicloud.openservices.tablestore.model.search.CreateSearchIndexRequest;
import com.alicloud.openservices.tablestore.model.search.CreateSearchIndexResponse;
import com.alicloud.openservices.tablestore.model.search.FieldSchema;
import com.alicloud.openservices.tablestore.model.search.FieldType;
import com.alicloud.openservices.tablestore.model.search.IndexSchema;
import com.alicloud.openservices.tablestore.model.search.SearchQuery;
import com.alicloud.openservices.tablestore.model.search.SearchRequest;
import com.alicloud.openservices.tablestore.model.search.SearchResponse;
import com.alicloud.openservices.tablestore.model.search.query.QueryBuilders;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
public class TestFuzzy {
private static final String tableName = "analysis_test";
private static final String indexName = "analysis_test_index";
public void testFuzzyMatchPhrase(SyncClient client) throws Exception {
// Define the table schema.
IndexSchema indexSchema = new IndexSchema();
indexSchema.setFieldSchemas(Collections.singletonList(
// Note: If the name field was originally of the Keyword type, queries may fail after you change the field type to Text and configure an analyzer.
// To retain both Keyword and Text types, see the example for the virtual column feature. If you only need to use the name field to perform queries that match *abc*, use only the Text type field. The Keyword type is not required.
new FieldSchema("name", FieldType.TEXT).setAnalyzer(FieldSchema.Analyzer.Fuzzy)
));
// Create a search index.
{
CreateSearchIndexRequest request = new CreateSearchIndexRequest();
request.setTableName(tableName);
request.setIndexName(indexName);
request.setIndexSchema(indexSchema);
CreateSearchIndexResponse response = client.createSearchIndex(request);
}
// Write a row of data.
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("1"))
.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(1))
.addPrimaryKeyColumn("pk3", PrimaryKeyValue.fromBinary(new byte[]{1, 2, 3}))
.build();
RowPutChange rowPutChange = new RowPutChange(tableName, primaryKey);
// Write an attribute column.
rowPutChange.addColumn("name", ColumnValue.fromString("Tuner1024x768P.mp4"));
PutRowRequest request = new PutRowRequest(rowPutChange);
client.putRow(request);
// Wait for the data to be synchronized to the search index.
Thread.sleep(1000 * 180);
// Demonstrate the query feature that matches *abc*.
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tun", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tun er", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner102", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024x", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024x7", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "Tuner1024x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "24x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name", "24x76 8P.mp4", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name", "24x7 P.mp4", 0);
}
// Use a virtual column.
public void testFuzzyMatchPhraseWithVirtualField(SyncClient client) throws Exception {
// Define the table schema.
IndexSchema indexSchema = new IndexSchema();
indexSchema.setFieldSchemas(Arrays.asList(
// The source field is of the Keyword type, which is convenient for exact match queries.
new FieldSchema("name", FieldType.KEYWORD).setIndex(true).setStore(true),
// Create a virtual column named name_virtual_text. Set the type of the virtual column to Text and the analyzer to Fuzzy. The source of this virtual column is the name field.
new FieldSchema("name_virtual_text", FieldType.TEXT).setIndex(true).setAnalyzer(FieldSchema.Analyzer.Fuzzy).setVirtualField(true).setSourceFieldName("name")
));
// Create a search index.
{
CreateSearchIndexRequest request = new CreateSearchIndexRequest();
request.setTableName(tableName);
request.setIndexName(indexName);
request.setIndexSchema(indexSchema);
CreateSearchIndexResponse response = client.createSearchIndex(request);
}
// Write a row of data.
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("1"))
.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(1))
.addPrimaryKeyColumn("pk3", PrimaryKeyValue.fromBinary(new byte[]{1, 2, 3}))
.build();
RowPutChange rowPutChange = new RowPutChange(tableName, primaryKey);
// Write an attribute column.
rowPutChange.addColumn("name", ColumnValue.fromString("Tuner1024x768P.mp4"));
PutRowRequest request = new PutRowRequest(rowPutChange);
client.putRow(request);
// Wait for the data to be synchronized to the search index.
Thread.sleep(1000 * 180);
// Demonstrate the query scenario that matches *abc*.
// Note that the query field is the virtual column name_virtual_text, not name.
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tun", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tun er", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner102", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024x", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024x7", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "Tuner1024x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "24x768P.mp4", 1);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "24x76 8P.mp4", 0);
assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "24x7 P.mp4", 0);
}
// Show how to implement MatchPhraseQuery.
public static void assertMatchPhraseQuery(SyncClient client, String tableName, String indexName, String fieldName, String searchContent, long exceptCount) {
SearchRequest searchRequest = new SearchRequest();
searchRequest.setTableName(tableName);
searchRequest.setIndexName(indexName);
SearchQuery searchQuery = new SearchQuery();
// Use MatchPhraseQuery to query the tokenized field.
searchQuery.setQuery(QueryBuilders.matchPhrase(fieldName, searchContent).build());
searchQuery.setLimit(0);
// To demonstrate the feature, this example returns the total number of matched rows. If you do not need the total count, set this to false for better performance.
searchQuery.setGetTotalCount(true);
searchRequest.setSearchQuery(searchQuery);
SearchResponse response = client.search(searchRequest);
assertEquals(String.format("field:[%s], searchContent:[%s]", fieldName, searchContent), exceptCount, response.getTotalCount());
}
}
Preguntas frecuentes
Referencias
Search Index admite diversos tipos de consultas para analizar datos multidimensionales, entre ellos term query, terms query, match all query, match query, phrase match query, range query, prefix query, suffix query, wildcard query, token-based wildcard query, boolean query, geo query, nested query, vector search, y exists query.
Al consultar datos, puede sort and paginate el conjunto de resultados o ejecutar collapsing (deduplication).
Para analizar datos, como buscar el valor máximo o mínimo, calcular una suma o contar filas, utilice las funciones statistical aggregation o SQL query.
Si necesita exportar datos rápidamente sin importar el orden del conjunto de resultados, utilice la función Parallel Scan.