Interroger un index de recherche IA
Vous pouvez query un index AI Search avec le SDK Python, l'API REST ou la fonction SQL vector_search(). AI Search prend en charge les types de query ANN, hybrides et en texte intégral, ainsi que la pagination, les filtres et le reranking pour affiner la qualité de la récupération.
Pour des Notebooks d'exemple illustrant comment créer et query des endpoints et des index de recherche IA, consultez les Notebooks d'exemple de recherche IA. Pour des informations de référence, consultez la référence du SDK Python.
Databricks AI Search était auparavant connu sous le nom de Databricks Vector Search.
Installation
Pour utiliser le SDK AI Search, vous devez l'installer dans votre notebook. Utilisez le code suivant pour installer le package :
%pip install databricks-ai-search
dbutils.library.restartPython()
Utilisez ensuite la commande suivante pour importer AISearchClient:
from databricks.ai_search.client import AISearchClient
Pour plus d'informations sur l'authentification, consultez Protection des données et authentification.
Comment interroger un index de recherche IA
Vous ne pouvez interroger l'index de recherche IA qu'en utilisant le SDK Python, l'API REST ou la fonction IA SQL vector_search().
Si l'utilisateur query l'index n'est pas le propriétaire de l'index AI Search, il doit disposer des privilèges UC suivants :
- USE CATALOG sur le catalogue qui contient l'index de recherche IA.
- USE SCHEMA sur le schéma qui contient l’index de recherche AI.
- SÉLECTIONNER sur l’index AI Search.
Le type de query par default est ann (voisin le plus proche approximatif). Pour plus de détails sur les différents algorithmes de récupération, consultez Algorithmes de récupération.
- Pour effectuer une recherche hybride par mots-clés et similarité, définissez le parameter
query_typesurhybrid. Par default, la recherche hybride inclut toutes les colonnes de métadonnées textuelles et renvoie un maximum de 200 résultats. - « Pour utiliser le réorganisateur dans une query, consultez Utiliser le réorganisateur dans une query. »
Bêta
La recherche en texte intégral est disponible en tant que fonctionnalité bêta. Pour effectuer une recherche en texte intégral, définissez le parameter query_type sur FULL_TEXT. Grâce à la recherche en texte intégral, vous pouvez récupérer jusqu'à 200 résultats basés sur la correspondance par mots-clés sans utiliser d'intégrations vectorielles. Les query en texte intégral sont prises en charge sur les Endpoint standard et optimisés pour le stockage. Sur les endpoints optimisés pour le stockage, vous pouvez également créer un index de recherche en texte intégral dédié sans intégrations. Consultez Créer un index de recherche en texte intégral (Bêta). Pour rechercher des colonnes de texte sélectionnées, trier les résultats ou renvoyer des totaux agrégés pour les query en texte intégral et hybrides, voir Rechercher des colonnes de texte sélectionnées, trier les résultats et renvoyer des agrégations (Bêta).
- Python SDK standard endpoint
- Python SDK storage-optimized endpoint
- REST API
- SQL
Pour plus de détails, consultez la référence du SDK Python.
# Delta Sync Index with embeddings computed by Databricks
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "field2"],
num_results=2
)
# Delta Sync Index using hybrid search, with embeddings computed by Databricks
results3 = index.similarity_search(
query_text="Greek myths",
columns=["id", "field2"],
num_results=2,
query_type="hybrid"
)
# Delta Sync Index using full-text search (Beta)
results4 = index.similarity_search(
query_text="Greek myths",
columns=["id", "field2"],
num_results=2,
query_type="FULL_TEXT"
)
# Delta Sync Index with pre-calculated embeddings
results2 = index.similarity_search(
query_vector=[0.9] * 1024,
columns=["id", "text"],
num_results=2
)
Pour plus de détails, consultez la référence du SDK Python.
L'interface de filtre existante a été repensée pour les index AI Search optimisés pour le stockage afin d'adopter une chaîne de filtre plus proche de SQL au lieu du dictionnaire de filtres utilisé dans les Endpoint AI Search standards.
client = AISearchClient()
index = client.get_index(index_name="vector_search_demo.vector_search.en_wiki_index")
# similarity search with query vector
results = index.similarity_search(
query_vector=[0.2, 0.33, 0.19, 0.52],
columns=["id", "text"],
num_results=2
)
# similarity search with query vector and filter string
results = index.similarity_search(
query_vector=[0.2, 0.33, 0.19, 0.52],
columns=["id", "text"],
# this is a single filter string similar to SQL WHERE clause syntax
filters="language = 'en' AND country = 'us'",
num_results=2
)
Consultez la documentation de référence de l'API REST : POST /api/2.0/vector-search/indexes/{index_name}/query.
Pour les applications de production, Databricks recommande d'utiliser des Service Principal au lieu de jetons d'accès personnels. En plus d'une sécurité et d'une gestion des accès améliorées, l'utilisation des Service Principal peut améliorer les performances jusqu'à 100 ms par query.
L'exemple de code suivant illustre comment interroger un index à l'aide d'un Service Principal.
export SP_CLIENT_ID=...
export SP_CLIENT_SECRET=...
export INDEX_NAME=...
export WORKSPACE_URL=https://...
export WORKSPACE_ID=...
# Set authorization details to generate OAuth token
export AUTHORIZATION_DETAILS='{"type":"unity_catalog_permission","securable_type":"table","securable_object_name":"'"$INDEX_NAME"'","operation": "ReadVectorIndex"}'
# If you are using an route_optimized embedding model endpoint, then you need to have additional authorization details to invoke the serving endpoint
# export EMBEDDING_MODEL_SERVING_ENDPOINT_ID=...
# export AUTHORIZATION_DETAILS="$AUTHORIZATION_DETAILS"',{"type":"workspace_permission","object_type":"serving-endpoints","object_path":"/serving-endpoints/'"$EMBEDDING_MODEL_SERVING_ENDPOINT_ID"'","actions": ["query_inference_endpoint"]}'
# Generate OAuth token
export TOKEN=$(curl -X POST --url $WORKSPACE_URL/oidc/v1/token -u "$SP_CLIENT_ID:$SP_CLIENT_SECRET" --data 'grant_type=client_credentials' --data 'scope=all-apis' --data-urlencode 'authorization_details=['"$AUTHORIZATION_DETAILS"']' | jq .access_token | tr -d '"')
# Get index URL
export INDEX_URL=$(curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" --url $WORKSPACE_URL/api/2.0/vector-search/indexes/$INDEX_NAME | jq -r '.status.index_url' | tr -d '"')
# Query AI Search index.
curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" --url https://$INDEX_URL/query --data '{"num_results": 3, "query_vector": [...], "columns": [...], "debug_level": 1}'
# Query AI Search index.
curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" --url https://$INDEX_URL/query --data '{"num_results": 3, "query_text": "...", "columns": [...], "debug_level": 1}'
L'exemple de code suivant illustre comment interroger un index à l'aide d'un jeton d'accès personnel (PAT).
export TOKEN=...
export INDEX_NAME=...
export WORKSPACE_URL=https://...
# Query AI Search index with `query_vector`
curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" --url $WORKSPACE_URL/api/2.0/vector-search/indexes/$INDEX_NAME/query --data '{"num_results": 3, "query_vector": [...], "columns": [...], "debug_level": 1}'
# Query AI Search index with `query_text`
curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" --url $WORKSPACE_URL/api/2.0/vector-search/indexes/$INDEX_NAME/query --data '{"num_results": 3, "query_text": "...", "columns": [...], "debug_level": 1}'
La fonction d'IA vector_search() est en prévisualisation publique.
Pour utiliser cette fonction IA, consultez la fonctionvector_search.
Pagination
Lorsqu'une query demande plus de 1 000 résultats, ceux-ci sont automatiquement renvoyés par pages de 1 000 au maximum. Le nombre maximal de résultats qu'une seule query peut renvoyer sur toutes les pages est de 10 000. Les Endpoint standard et optimisés pour le stockage prennent en charge la pagination.
La pagination fonctionne avec tous les types de requêtes.
- Python SDK
- REST API
Le SDK Python gère la pagination de manière transparente. Lorsque vous définissez num_results sur une valeur supérieure à 1 000, le SDK récupère automatiquement toutes les pages et renvoie le jeu de résultats complet. Aucun code supplémentaire n'est requis.
# The SDK automatically paginates and returns all 5000 results
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "text"],
num_results=5000
)
Lorsque vous utilisez l'API REST directement, vous devez gérer la pagination manuellement. Si plus de résultats sont disponibles, la réponse inclut un champ next_page_token. Pour récupérer la page suivante des résultats, transmettez ce jeton à l'Endpoint de query-next-page.
Consultez la documentation de référence de l'API REST : POST /api/2.0/vector-search/indexes/{index_name}/query-next-page.
export TOKEN=...
export INDEX_NAME=...
export WORKSPACE_URL=https://...
# Initial query - if num_results exceeds 1000, the response includes next_page_token
curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \
--url $WORKSPACE_URL/api/2.0/vector-search/indexes/$INDEX_NAME/query \
--data '{"num_results": 5000, "query_text": "...", "columns": ["id", "text"]}'
# Use next_page_token from the response to get the next page
curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \
--url $WORKSPACE_URL/api/2.0/vector-search/indexes/$INDEX_NAME/query-next-page \
--data '{"page_token": "<next_page_token from previous response>"}'
Continuez à appeler l'Endpoint de query-next-page avec le next_page_token de chaque réponse jusqu'à ce que le jeton soit vide ou absent, ce qui indique que tous les résultats ont été renvoyés.
Utiliser des filtres sur les query
Une query peut définir des filtres basés sur n'importe quelle colonne de la table Delta. similarity_search renvoie uniquement les lignes qui correspondent aux filtres spécifiés.
Le tableau suivant répertorie les filtres pris en charge.
Pour les Endpoint optimisés pour le stockage, les résultats sont sur-récupérés. Si vous définissez num_results à k, plus de k résultats sont récupérés, et le filtre est appliqué aux résultats récupérés. Il est possible qu'aucun résultat ne soit renvoyé même s'il existe des résultats dans le dataset qui correspondent à la condition de filtre, si le score de ces documents ne fait pas partie des meilleurs.
Opérateur de filtre | Comportement | Exemples |
|---|---|---|
| Standard : annule le filtre. La clé doit se terminer par « NOT ». Par exemple, « color NOT » avec la valeur « red » correspond aux documents dont la couleur n'est pas rouge. Optimisé pour le stockage : consultez | Standard : Optimisé pour le stockage : |
| Standard : vérifie si la valeur du champ est inférieure à la valeur du filtre. La clé doit se terminer par Optimisé pour le stockage : voir l'opérateur | Standard : Optimisé pour le stockage : |
| Standard : vérifie si la valeur du champ est inférieure ou égale à la valeur du filtre. La clé doit se terminer par Stockage optimisé : consultez l' | Standard : Optimisé pour le stockage : |
| Standard : vérifie si la valeur du champ est supérieure à la valeur du filtre. La clé doit se terminer par **Stockage optimisé** : Voir | Standard : Optimisé pour le stockage : |
| Standard : Vérifie si la valeur du champ est supérieure ou égale à la valeur du filtre. La clé doit se terminer par Stockage optimisé : voir | Standard : Optimisé pour le stockage : |
| Standard : Vérifie si la valeur du champ correspond à l'une des valeurs de filtre. La clé doit contenir Optimisé pour le stockage : Consultez l' | Standard : Optimisé pour le stockage : |
| Standard : correspond aux jetons séparés par des espaces dans une chaîne. Optimisé pour le stockage : Consultez l' | Consultez les Notes sur l'utilisation de |
Aucun opérateur de filtre spécifié | Standard : Le filtre vérifie la correspondance exacte. Si plusieurs valeurs sont spécifiées, elle correspond à l'une des valeurs. Stockage optimisé : voir | Standard : Optimisé pour le stockage : |
| Optimisé pour le stockage : Filtrez sur un timestamp. Consulter la fonction | Optimisé pour le stockage : |
Notes sur l'utilisation de LIKE
LIKE exemples pour les Endpoint standard
{"column LIKE": "apple"}: correspond aux chaînes « apple » et « apple pear », mais ne correspond pas à « pineapple ». Notez qu'il ne correspond pas à « pineapple » même s'il contient une sous-chaîne « apple » — il recherche une correspondance exacte sur des jetons séparés par des espaces blancs comme dans « apple pear ».
{"column NOT LIKE": "apple"} fait le contraire. Il correspond à « pineapple » et « pear », mais ne correspond pas à « apple » ou « apple pear ».
LIKE exemples d'Endpoint optimisés pour le stockage
Format | Correspondances |
|---|---|
| Équivalent à l'opérateur |
| Renvoie les lignes où un préfixe correspond à |
| Renvoie les lignes dont le suffixe correspond à |
| Renvoie les lignes qui contiennent une sous-chaîne qui correspond à |
Exemples de code
- Python SDK standard endpoint
- Python SDK storage-optimized endpoint
- REST API
# Match rows where `title` exactly matches `Athena` or `Ares`
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "text"],
filters={"title": ["Ares", "Athena"]},
num_results=2
)
# Match rows where `title` or `id` exactly matches `Athena` or `Ares`
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "text"],
filters={"title OR id": ["Ares", "Athena"]},
num_results=2
)
# Match only rows where `title` is not `Hercules`
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "text"],
filters={"title NOT": "Hercules"},
num_results=2
)
# Match rows where `title` exactly matches `Athena` or `Ares`
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "text"],
filters='title IN ("Ares", "Athena")',
num_results=2
)
# Match rows where `title` or `id` exactly matches `Athena` or `Ares`
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "text"],
filters='title = "Ares" OR id = "Athena"',
num_results=2
)
# Match only rows where `title` is not `Hercules`
results = index.similarity_search(
query_text="Greek myths",
columns=["id", "text"],
filters='title != "Hercules"',
num_results=2
)
Rechercher les colonnes de texte sélectionnées, trier les résultats et renvoyer les agrégations (Bêta)
Bêta
Les options de recherche de colonnes de texte sélectionnées, de tri et de retour d'agrégations font partie de la version bêta **Vector Search : Recherche plein texte**. Pour utiliser,,query_columns sort_columns facetsou, activez l'aperçu public **Vector Search : Recherche plein texte**. Contactez votre équipe de compte ou consultez Gérer les aperçus Databricks pour activer les aperçus.
Utilisez ces options pour rechercher des champs de texte sélectionnés, appliquer un ordre de résultats explicite ou renvoyer des agrégations pour les résultats correspondants.
Ces options sont prises en charge pour les requêtes en texte intégral et hybrides. Elles ne sont pas prises en charge pour les requêtes ANN.
Rechercher les colonnes de texte sélectionnées
Utilisez query_columns pour rechercher uniquement les colonnes de texte spécifiées. Si vous l'omettez, la requête recherche toutes les colonnes de texte.
query_columns=["title", "text"]
Trier les résultats
Utilisez sort_columns pour classer les résultats par valeurs de colonne au lieu de l'ordre de pertinence par default. Les entrées utilisent le format "<column> ASC" ou "<column> DESC".
sort_columns=["rating DESC", "publication_year DESC"]
Retournez les agrégations
Utilisez facets pour renvoyer les comptes agrégés pour les résultats correspondants.
Les facettes de valeur comptent les résultats correspondants par valeurs distinctes dans une colonne, telle que la langue ou la catégorie. TOP limite le nombre de valeurs renvoyées et est défini par default sur 10 s'il est omis.
facets=["language TOP 5"]
Exemple de réponse :
{
"facet_result": {
"facet_array": [
["language", "en", 28],
["language", "el", 14]
]
}
}
Les buckets numériques comptent les résultats correspondants qui se situent dans des plages numériques spécifiées, telles que les années de publication ou les prix. Les limites du bucket sont inclusives.
facets=["publication_year BUCKETS [[1900,1949],[1950,1999],[2000,2025]]"]
Exemple de réponse :
{
"facet_result": {
"facet_array": [
["publication_year", "[1900,1949]", 8],
["publication_year", "[1950,1999]", 14],
["publication_year", "[2000,2025]", 20]
]
}
}
Pour les requêtes en texte intégral, la Recherche IA calcule des agrégations sur tous les résultats qui correspondent à la requête et aux filtres, et pas seulement les lignes renvoyées dans la réponse. Pour les requêtes hybrides, AI Search applique le tri et les agrégations à l'ensemble de candidats borné que la recherche hybride produit, et non à chaque ligne de l'index.
Pour les champs de requête et le schéma de réponse de l'API REST, consultez POST /api/2.0/vector-search/indexes/{index_name}/query.
Utilisez le réorganisateur dans une query
Les performances de l'agent dépendent de la récupération des informations les plus pertinentes pour une query. Le réordonnancement est une technique qui améliore la qualité de la récupération en évaluant les documents récupérés pour identifier ceux qui sont sémantiquement les plus pertinents. Databricks a développé un système d'IA composé basé sur la recherche pour identifier ces documents. Vous pouvez également spécifier les colonnes contenant des métadonnées que vous souhaitez que le réordonnanceur utilise pour un contexte supplémentaire lorsqu'il évalue la pertinence de chaque document.
Le reranking entraîne un léger délai de latence, mais peut améliorer considérablement la qualité de récupération et les performances de l'agent. Databricks recommande d'essayer le reclassement pour tout cas d'utilisation d'agent RAG.
Le réordonnanceur de recherche IA est un service désigné Databricks qui utilise Databricks Geos pour gérer la résidence des données. Les clients en dehors des États-Unis et de l'UE pourraient avoir besoin d' activer le traitement inter-géographique pour utiliser le réordonnanceur.
Les exemples de cette section montrent comment utiliser le réorganisateur AI Search. Lorsque vous utilisez le réorganisateur, vous définissez séparément les colonnes à renvoyer (columns) et les colonnes de métadonnées à utiliser pour le reclassement (columns_to_rerank). num_results est le nombre final de résultats à renvoyer. Cela n'affecte pas le nombre de résultats utilisés pour le reclassement.
Le message de débogage de la query comprend des informations sur le temps qu'a pris l'étape de reclassement. Par exemple :
'debug_info': {'response_time': 693.0, 'ann_time': 29.0, 'reranker_time': 619.0}
Si l'appel du reranker échoue, cette information est incluse dans le message de débogage :
'debug_info': {'response_time': 587.0, 'ann_time': 331.0, 'reranker_time': 246.0, 'warnings': [{'status_code': 'RERANKER_TEMPORARILY_UNAVAILABLE', 'message': 'The reranker is temporarily unavailable. Results returned have not been processed by the reranker. Please try again later for reranked results.'}]}
L'ordre dans lequel les colonnes sont listées dans columns_to_rerank est important. Le calcul de reclassement prend les colonnes dans l'ordre où elles sont listées et ne prend en compte que les 2 000 premiers caractères qu'il trouve.
- Python SDK
- REST API
# Install the most recent version.
# Databricks SDK version 0.57 or above is required to use the reranker.
%pip install databricks-ai-search --force-reinstall
dbutils.library.restartPython()
from databricks.ai_search.reranker import DatabricksReranker
results = index.similarity_search(
query_text = "How to create an AI Search index",
columns = ["id", "text", "parent_doc_summary", "date"],
num_results = 10,
query_type = "hybrid",
reranker=DatabricksReranker(columns_to_rerank=["text", "parent_doc_summary", "other_column"])
)
Pour vous assurer d'obtenir les informations sur la latence, définissez debug_level sur au moins 1.
export TOKEN=...
export INDEX_NAME=...
export WORKSPACE_URL=https://...
curl -X GET -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" --url $WORKSPACE_URL/api/2.0/vector-search/indexes/$INDEX_NAME/query --data '{"num_results": 10, "query_text": "How to create an AI Search index", "columns": ["id", "text", "parent_doc_summary", "date"], "reranker": {"model": "databricks_reranker",
"parameters": {
"columns_to_rerank":
["text", "parent_doc_summary"]
}
},
"debug_level": 1}'
Recherches de points
Pour effectuer une recherche ponctuelle, utilisez un filtre sur n'importe quelle colonne de clé primaire.
Algorithmes de récupération
Cette section décrit les différents algorithmes de récupération ou types de query et quand chacun peut être utilisé. Utilisez le parameter query_type pour spécifier l'algorithme de récupération à utiliser. Pour comparer automatiquement les performances de différents algorithmes pour votre index, consultez Évaluer la qualité de la récupération de la recherche IA.
Stratégie | Comment ça marche | Idéal pour |
|---|---|---|
ANN (plus proche voisin approximatif) | Recherches utilisant des incorporations vectorielles pour trouver des documents sémantiquement similaires. | Requêtes conceptuelles et sémantiques où le sens est plus important que le libellé exact. |
Texte intégral | Recherche par mots-clés qui correspond à des termes exacts. | Requêtes avec des termes spécifiques, des noms propres, des ID de produits ou du jargon technique. |
Hybride | Combine les résultats ANN et textuels complets à l'aide de la fusion de rang réciproque (RRF). | Récupération à usage général. Le point de départ recommandé pour la plupart des cas d'usage. |
Hybride + réorganisateur | Exécute une recherche hybride, puis reclasse les résultats avec un modèle de reclassement cross-encoder. | Précision supérieure lorsque la latence le permet (généralement moins d'une seconde supplémentaire par query). |
ANN (Vector Search)
La recherche ANN convertit une query en une incorporation vectorielle et trouve les documents dont les incorporations sont les plus similaires. Ceci est efficace pour comprendre le sens . Par exemple, une query telle que « comment réparer un tuyau cassé » correspond à des documents sur la plomberie même s’ils ne contiennent pas ces mots exacts.
- Quand l'ANN est performant : Les requêtes sont conceptuelles, conversationnelles ou utilisent un vocabulaire différent de celui des documents.
- Quand l'ANN peut être sous-performante : les query reposent sur des mots-clés exacts, des noms propres ou une terminologie spécifique au domaine que les intégrations peuvent ne pas saisir précisément.
Recherche plein texte (recherche par mot-clé)
La recherche plein texte met en correspondance les documents contenant les termes de requête. La recherche en texte intégral a une grande précision. Lorsque les utilisateurs recherchent des noms, des codes ou des termes techniques spécifiques, la correspondance par mots-clés trouve des correspondances exactes que la recherche vectorielle pourrait manquer.
Utilisez les options de requête en texte intégral ou hybrides pour rechercher des colonnes de texte sélectionnées, trier les résultats ou renvoyer des totaux agrégés. Voir Rechercher les colonnes de texte sélectionnées, trier les résultats et renvoyer les agrégations (Bêta).
- Quand la recherche en texte intégral est performante : les queries contiennent des identifiants spécifiques, des noms de produits, des codes d'erreur ou une terminologie spécifique au domaine.
- Quand la recherche en texte intégral peut être moins performante : les query sont formulées différemment des documents ou utilisent des synonymes et des paraphrases.
Recherche hybride
La recherche hybride exécute en parallèle les recherches ANN et en texte intégral, puis Merge les résultats à l’aide de Reciprocal Rank Fusion (RRF). Cela combine la compréhension sémantique de la recherche vectorielle avec la précision de la correspondance par mot-clé.
- Quand la recherche hybride est performante : La charge de travail des requêtes est un mélange de requêtes conceptuelles et de requêtes à forte densité de mots-clés. L'hybride est la stratégie la plus robuste à usage général.
Réorganisateur
Le réorganisateur est une deuxième passe facultative appliquée en plus de toute stratégie. Après la récupération initiale, un modèle d’encodeur croisé réévalue chaque résultat dans le contexte de la query, ce qui produit un ordre de pertinence plus précis.
Le réorganisateur améliore généralement la qualité d'environ 10 %, mais il ajoute de la latence. Il est adapté aux applications où la qualité est primordiale, telles que les chatbots RAG, mais potentiellement moins adapté aux applications de recherche à throughput élevé et à faible latence.