Tous les produits
Search
Centre de documentation

Tablestore:Requête générique basée sur la tokenisation

Dernière mise à jour :Aug 18, 2026

Si vous effectuez une requête générique pour rechercher la chaîne *word*, vous pouvez utiliser une requête générique basée sur la tokenisation (combinaison de tokenisation floue et de requête de correspondance d'expression) afin de garantir de meilleures performances de requête.

Contexte

La requête floue est une exigence courante dans les bases de données. Par exemple, vous pouvez effectuer une requête floue pour interroger des noms de fichiers et des numéros de téléphone mobile. Pour effectuer des requêtes floues dans Tablestore, vous pouvez utiliser la fonctionnalité de requête générique des index de recherche. Cette fonctionnalité est similaire à l'opérateur LIKE dans MySQL. Toutefois, la requête générique prend en charge uniquement jusqu'à 32 caractères dans la chaîne utilisée pour la requête, et les performances de la requête diminuent à mesure que la taille des données augmente.

Pour résoudre ces problèmes, les index de recherche prennent en charge les requêtes génériques basées sur la tokenisation afin de garantir des performances élevées lors des requêtes floues. Lorsque vous utilisez des requêtes génériques basées sur la tokenisation, Tablestore ne limite pas la longueur de la chaîne utilisée pour une requête. Cependant, si la valeur de la colonne dépasse 1 024 caractères, le système tronque la valeur de la colonne et n'effectue la tokenisation que pour les 1 024 premiers caractères.

Scénarios

Sélectionnez une méthode adaptée à votre scénario pour effectuer une requête floue.

  • Si vous utilisez *word* pour une requête générique, vous pouvez utiliser des requêtes génériques basées sur la tokenisation pour effectuer une requête floue. Par exemple, si vous utilisez "123" pour interroger les numéros de téléphone mobile qui contiennent 123 à n'importe quelle position, vous pouvez utiliser des requêtes génériques basées sur la tokenisation pour effectuer une requête floue.

    Dans ce cas, une requête générique basée sur la tokenisation améliore les performances de la requête de plus de 10 fois par rapport à une requête générique standard.

    Par exemple, une table de données contient une colonne nommée file_name, le type de colonne est Text et la méthode de tokenisation est la tokenisation floue (FuzzyAnalyzer) pour la colonne dans l'index de recherche. Si vous utilisez l'index de recherche pour interroger les lignes dont la valeur de la colonne file_name est 2021 woRK@Hangzhou, vous devez effectuer une requête de correspondance d'expression (MatchPhraseQuery) et définir les tokens comme des sous-chaînes consécutives pour la requête.

    • Si le token pour la requête est 2021, 20, 21, work, WORK, @, Hang, zhou, Hangzhou ou @Hangzhou, les lignes dont la valeur de la colonne file_name est 2021 woRK@Hangzhou peuvent correspondre au token.

    • Si le token pour la requête est 21work, 2021Hangzhou, 2120 ou #Hangzhou, les lignes dont la valeur de la colonne file_name est 2021 woRK@Hangzhou ne peuvent pas correspondre au token.

  • Pour d'autres requêtes complexes, vous pouvez utiliser des requêtes génériques pour les requêtes floues. Pour plus d'informations, consultez la rubrique Requête générique.

Utiliser la tokenisation floue pour une requête floue

Pour utiliser des requêtes génériques basées sur la tokenisation pour une requête floue, procédez comme suit :

  1. Créez un index de recherche. Lors de la création d'un index de recherche, définissez le type de champ sur Text et la méthode de tokenisation sur tokenisation floue (FuzzyAnalyzer) pour la colonne spécifiée, et conservez les paramètres par défaut pour les autres paramètres. Pour plus d'informations, consultez la rubrique Créer un index de recherche.

    Remarque

    Si un index de recherche existe déjà, vous pouvez ajouter une colonne virtuelle pour la colonne spécifiée en modifiant dynamiquement le schéma de l'index de recherche. Définissez ensuite le type de champ sur Text et la méthode de tokenisation sur tokenisation floue pour la colonne virtuelle. Pour plus d'informations, consultez les rubriques Modifier dynamiquement le schéma d'un index de recherche et Colonnes virtuelles.

  2. Utilisez l'index de recherche pour interroger les données. Lorsque vous utilisez l'index de recherche pour interroger les données, effectuez une requête de correspondance d'expression. Pour plus d'informations, consultez la rubrique Requête de correspondance d'expression.

Annexe : cas de test

Les cas de test suivants montrent comment utiliser des requêtes génériques basées sur la tokenisation pour effectuer une requête floue :

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

Références