Todos os produtos
Search
Central de documentação

Tablestore:Consulta com curinga baseada em tokenização

Última atualização: Jul 03, 2026

Ao buscar a string *word* com uma consulta com curinga, use a consulta com curinga baseada em tokenização (combinação de tokenização difusa e consulta de correspondência de frase) para garantir melhor desempenho.

Informações básicas

Consultas difusas são comuns em bancos de dados, como na busca por nomes de arquivos ou números de celular. No Tablestore, use o recurso de consulta com curinga dos índices de pesquisa, semelhante ao operador LIKE do MySQL. Contudo, esse recurso aceita no máximo 32 caracteres na string de busca, e o desempenho diminui conforme o volume de dados aumenta.

Para resolver essas limitações, os índices de pesquisa oferecem consultas com curinga baseadas em tokenização, que mantêm alto desempenho em buscas difusas. Nesse modo, o Tablestore não impõe limite ao tamanho da string de consulta. Entretanto, se o valor da coluna ultrapassar 1.024 caracteres, o sistema trunca esse valor e aplica a tokenização apenas nos primeiros 1.024 caracteres.

Cenários

Escolha o método mais adequado ao seu cenário para executar consultas difusas.

  • Para buscas com o padrão *word*, prefira consultas com curinga baseadas em tokenização. Por exemplo, ao pesquisar números de celular contendo "123" em qualquer posição usando "123", essa abordagem oferece resultados mais eficientes.

    Nesse caso, a consulta com curinga baseada em tokenização melhora o desempenho em mais de 10 vezes em comparação à consulta com curinga tradicional.

    Considere uma tabela com a coluna file_name do tipo Text, configurada com tokenização difusa (FuzzyAnalyzer) no índice de pesquisa. Para encontrar linhas em que file_name seja 2021 woRK@Hangzhou, execute uma consulta de correspondência de frase (MatchPhraseQuery) definindo tokens como substrings consecutivas.

    • Tokens como 2021, 20, 21, work, WORK, @, Hang, zhou, Hangzhou ou @Hangzhou correspondem às linhas com valor 2021 woRK@Hangzhou na coluna file_name.

    • Já tokens como 21work, 2021Hangzhou, 2120 ou #Hangzhou não encontram correspondência nas linhas em que file_name é 2021 woRK@Hangzhou.

  • Em situações mais complexas, use as consultas com curinga tradicionais. Consulte Consulta com curinga para mais detalhes.

Uso de tokenização difusa para consultas difusas

Siga as etapas abaixo para aplicar consultas com curinga baseadas em tokenização:

  1. Crie um índice de pesquisa. Defina o tipo do campo como Text e o método de tokenização como difuso (FuzzyAnalyzer) para a coluna desejada, mantendo os demais parâmetros com as configurações padrão. Veja mais em Criar um índice de pesquisa.

    Nota

    Se já existir um índice de pesquisa, adicione uma coluna virtual para a coluna especificada modificando dinamicamente o esquema do índice. Em seguida, configure o tipo do campo como Text e o método de tokenização como difuso para essa coluna virtual. Para mais informações, consulte Modificar dinamicamente o esquema de um índice de pesquisa e Colunas virtuais.

  2. Consulte os dados usando o índice de pesquisa. Execute uma consulta de correspondência de frase durante a busca. Consulte Consulta de correspondência de frase para detalhes.

Apêndice: casos de teste

Os exemplos a seguir demonstram como usar consultas com curinga baseadas em tokenização para buscas difusas:

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 {
        // Specify the schema of a search index. 
        IndexSchema indexSchema = new IndexSchema();
        indexSchema.setFieldSchemas(Collections.singletonList(
                // Note: If you specify Text as the type of the name field that is mapped to the name column of the Keyword type in a data table and set the tokenization method for the field, exceptions may occur in the query. 
                // If you want to retain both the Keyword and Text types, see the example provided in the "Virtual columns" topic. If you use *abc* to match the name field, only the name field of the Text type is required. The name field of the Keyword type is not required. 
                new FieldSchema("name", FieldType.TEXT).setAnalyzer(FieldSchema.Analyzer.Fuzzy)
        ));
        // Create the 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 to the data table. 
        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);
        // Specify the attribute column of the row. 
        rowPutChange.addColumn("name", ColumnValue.fromString("TheLionKing1024x768P.mp4"));
        PutRowRequest request = new PutRowRequest(rowPutChange);
        client.putRow(request);

        // Wait until the row of data is synchronized to the search index. 
        Thread.sleep(1000 * 180);

        // Use *abc* for the query. 
        assertMatchPhraseQuery(client, tableName, indexName, "name", "The", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name", "TheLion", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name", "The Lion", 0);
        assertMatchPhraseQuery(client, tableName, indexName, "name", "TheLionKing102", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name", "TheLionKing1024", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name", "TheLionKing1024x", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name", "TheLionKing1024x7", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name", "TheLionKing1024x768P.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 {
        // Specify the schema of a search index. 
        IndexSchema indexSchema = new IndexSchema();
        indexSchema.setFieldSchemas(Arrays.asList(
                // Set the type of the name field to Keyword, which facilitates equivalent queries. 
                new FieldSchema("name", FieldType.KEYWORD).setIndex(true).setStore(true),
                // Create a virtual column named name_virtual_text and set the field type to Text and the tokenization method to Fuzzy for the virtual column. The data source of the virtual column is the name field. 
                new FieldSchema("name_virtual_text", FieldType.TEXT).setIndex(true).setAnalyzer(FieldSchema.Analyzer.Fuzzy).setVirtualField(true).setSourceFieldName("name")
        ));
        // Create the 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 to the data table. 
        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);
        // Specify the attribute column of the row. 
        rowPutChange.addColumn("name", ColumnValue.fromString("TheLionKing1024x768P.mp4"));
        PutRowRequest request = new PutRowRequest(rowPutChange);
        client.putRow(request);

        // Wait until the row of data is synchronized to the search index. 
        Thread.sleep(1000 * 180);

        // Use *abc* for the query. 
        // Note: The field for the query is name_virtual_text instead of name. 
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "The", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "TheLion", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "The Lion", 0);
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "TheLionKing102", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "TheLionKing1024", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "TheLionKing1024x", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "TheLionKing1024x7", 1);
        assertMatchPhraseQuery(client, tableName, indexName, "name_virtual_text", "TheLionKing1024x768P.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);
    }

    // Perform a match phrase query. 
    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();
        // Perform a match phrase query to query data that matches the tokens. 
        searchQuery.setQuery(QueryBuilders.matchPhrase(fieldName, searchContent).build());
        searchQuery.setLimit(0);
        // Specify that the total number of matched rows is returned. If you are not concerned about the total number of matched rows, set this parameter 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());
    }
}

FAQ

Referências