TairSearch est un module de recherche en texte intégré à Tair (compatible avec Redis OSS). Il utilise une syntaxe de requête similaire à celle d'Elasticsearch, offrant des performances d'écriture et de recherche de l'ordre de la milliseconde.
Présentation
TairSearch offre les fonctionnalités suivantes :
Faible latence et hautes performances : Écriture et recherche en texte intégral à l'échelle de la milliseconde, propulsées par le moteur en mémoire de Tair. Pour plus de détails, consultez le livre blanc sur les performances de TairSearch.
Mises à jour incrémentielles et partielles : Ajoutez, mettez à jour, supprimez ou incrémentez automatiquement des champs individuels de document sans avoir à réécrire le document entier.
Syntaxe de requête semblable à Elasticsearch : DSL de requête basé sur JSON prenant en charge
bool,match,term, la pagination et le tri, familier aux développeurs ayant une expérience d'Elasticsearch.Agrégation : Agrégations
terms, métriques etfilterpour l'analyse des résultats de recherche. Consultez la section Agrégations.Saisie semi-automatique : Correspondance floue basée sur le préfixe pour une expérience de recherche au fil de la frappe.
Analyseurs intégrés et personnalisés : Analyseurs intégrés pour l'anglais (
standard,stop), le chinois (jieba,IK) et d'autres langues. Les analyseurs personnalisés avec des dictionnaires définis par l'utilisateur et des mots vides sont également pris en charge. Pour plus de détails, consultez la rubrique Analyseurs de recherche.Requête d'index fragmenté : Effectuez des recherches sur plusieurs index fragmentés avec
TFT.MSEARCHet obtenez des résultats agrégés.Compression des documents : Compressez les documents stockés pour réduire l'utilisation de la mémoire. Désactivé par défaut.
Mise en cache des requêtes : Mettez en cache les résultats des requêtes récentes pour améliorer les performances des requêtes sur les données fréquemment accédées.
Prérequis
L'instance doit être une instance Tair optimisée pour la mémoire (basée sur DRAM) exécutant l'une des versions suivantes :
|
Version du moteur |
Version mineure minimale |
|
Compatible avec Redis 5.0 |
1.7.27 ou ultérieure |
|
Compatible avec Redis 6.0 |
6.2.4.1 ou ultérieure |
|
Compatible avec Redis 7.0 |
Toutes les versions mineures |
Mettez à jour l'instance vers la dernière version mineure pour bénéficier du plus grand nombre de fonctionnalités et d'une stabilité optimale. Pour obtenir des instructions, consultez la rubrique Mettre à niveau les versions mineures et proxy. Pour les instances en cluster ou avec séparation lecture/écriture, mettez également à jour les nœuds proxy vers la dernière version mineure afin de garantir que toutes les commandes fonctionnent comme prévu.
Notes de version
Instances basées sur DRAM compatibles avec Redis 5.0
|
Date |
Version |
Modifications |
|
2022-03-11 |
V1.7.27 |
Lancement de TairSearch |
|
2022-05-24 |
V1.8.5 |
Fonctionnalité d'agrégation |
|
2022-09-06 |
V5.0.15 |
Commande |
|
2023-01-13 |
V5.0.25 |
Analyseurs |
|
2023-03-15 |
V5.0.28 |
Mise en cache des requêtes, compression des documents, commande |
|
2023-06-12 |
V5.0.35 |
Type de données ARRAY, algorithme de similarité Okapi BM25 |
Instances basées sur DRAM compatibles avec Redis 6.0
|
Date |
Version |
Modifications |
|
2023-02-07 |
V6.2.4.1 |
TairSearch (toutes les fonctionnalités de la V5.0.25) |
|
2023-03-14 |
V6.2.5.0 |
Mise en cache des requêtes, compression des documents, |
|
2023-06-12 |
V6.2.7.3 |
Type de données ARRAY, Okapi BM25 (toutes les fonctionnalités de la V5.0.35) |
|
2023-12-21 |
V23.12.1.2 |
Commande |
Instances basées sur DRAM compatibles avec Redis 7.0
|
Date |
Version |
Modifications |
|
2024-07-22 |
V24.7.0.0 |
Prise en charge de TairSearch |
Bonnes pratiques
Accélérer les requêtes avec des index multicolonnes à l'aide de TairSearch
Générer des graphiques en chandeliers pour les actions boursières à l'aide de TairSearch
Utiliser la requête bool pour effectuer des requêtes composées dans TairSearch
Utiliser Msearch dans TairSearch pour rechercher des documents par fragment de données
Remarques sur l'utilisation
Les données TairSearch sont stockées sur l'instance Tair et consomment la mémoire de l'instance.
-
Pour réduire l'utilisation de la mémoire :
Définissez
indexsurtrueuniquement pour les champs qui doivent être recherchables. Définissezindexsurfalsepour les autres champs.Utilisez
_sourceavec les motifsincludes/excludespour stocker uniquement les champs de document dont vous avez besoin.Choisissez un analyseur approprié pour éviter une tokenisation inutile et une augmentation de l'utilisation de la mémoire.
Activez la compression des documents pour les documents volumineux.
Maintenez le nombre de documents par index inférieur à 5 millions. Cela permet d'éviter le déséquilibre des données dans les instances en cluster, d'équilibrer les requêtes de lecture et d'écriture, et de réduire les clés volumineuses et les clés chaudes. Répartissez les grands ensembles de données sur plusieurs index et utilisez
TFT.MSEARCHpour les interroger conjointement.
Conventions de syntaxe
|
Convention |
Signification |
|
|
|
Mot-clé de commande |
|
|
italique |
Variable |
|
|
|
Paramètre facultatif. Les paramètres sans crochets sont obligatoires. |
|
|
`A\ |
B` |
Paramètres mutuellement exclusifs. Spécifiez-en un seul. |
|
|
Le paramètre précédent peut être répété. |
Commandes de recherche en texte intégral
TFT.CREATEINDEX
Crée un index avec une définition de mappage. La syntaxe de mappage est similaire au mappage explicite d'Elasticsearch. Un index doit être créé avant que des documents puissent être ajoutés.
Syntaxe
TFT.CREATEINDEX index mappings [settings]
Pour éviter les clés volumineuses, divisez les grands index en index plus petits avec desmappingset dessettingsidentiques, puis interrogez-les conjointement avecTFT.MSEARCH.
Paramètres
|
Paramètre |
Obligatoire |
Description |
|
index |
Oui |
Nom de l'index à créer. |
|
mappings |
Oui |
Définition du mappage JSON. Consultez la section Options de mappage. |
|
settings |
Non |
Paramètres JSON pour l'index. Consultez la section Paramètres d'index. |
Options de mappage
L'objet mappings prend en charge les champs de premier niveau suivants :
dynamic
Mode de mappage. Valeurs possibles :
"strict"-- Les données ne peuvent être écrites que dans les champs définis dansproperties. L'écriture dans des champs non définis échoue.Non spécifié (par défaut) -- Mode non strict. Le système ne vérifie pas si les champs écrits sont définis dans
properties.
enabled
Contrôle la vérification de type pour les champs non indexés (index défini sur false). Valeurs possibles : true (par défaut) et false. Lorsque true, une écriture échoue si le type de champ ne correspond pas au type défini dans properties. Les champs indexés font toujours l'objet d'une vérification de type, indépendamment de ce paramètre.
_source
Contrôle si le document original est stocké. Ce paramètre n'affecte pas la création de l'index.
enabled--true(par défaut) stocke le document original.falsene le stocke pas.includes-- Tableau de motifs de noms de champs à inclure. Les caractères génériques sont pris en charge.excludes-- Tableau de motifs de noms de champs à exclure. Les caractères génériques sont pris en charge. Si un champ correspond à la fois àincludeset àexcludes,excludesa la priorité (le champ n'est pas stocké).
Exemples :
"_source": {"enabled": true}
Il s'agit de la valeur par défaut : tous les champs sont stockés. Équivalent à "_source": {"enabled": true, "excludes": [], "includes": []}.
"_source": {"enabled": true, "excludes": [], "includes": ["id", "name"]}
Stocke uniquement les champs id et name.
properties
Collection de définitions de champs. Chaque champ prend en charge les attributs suivants :
|
Attribut |
Description |
Par défaut |
|
|
Type de données. Consultez la section Types de champs. |
Obligatoire |
|
|
Indique si ce champ est indexé (recherchable). |
|
|
|
Pondération du champ pour le score. Nombre à virgule flottante positif. |
|
|
|
Algorithme de similarité : |
|
Types de champs
|
Type |
Description |
Options spécifiques au type |
|
|
Chaîne non tokenisée. Adaptée aux requêtes de correspondance exacte. |
|
|
|
Chaîne tokenisée par un analyseur avant l'indexation. |
|
|
|
Entier 64 bits. Adapté aux horodatages (époque Unix). |
-- |
|
|
Entier 32 bits. |
-- |
|
|
Nombre à virgule flottante 64 bits. |
-- |
Prise en charge des tableaux (ARRAY) : Tous les types de champs prennent en charge les variantes de tableau. Ajoutez [] au nom du type. Par exemple, keyword[] déclare un tableau de mots-clés.
TFT.CREATEINDEX idx:products '{"mappings":{"properties":{"tags":{"type":"keyword[]"}}}}'
Options de l'analyseur de texte
|
Option |
Description |
Par défaut |
|
|
Analyseur utilisé pour l'indexation. Consultez la section Analyseurs intégrés. Des analyseurs personnalisés peuvent également être spécifiés et configurés via la section |
|
|
|
Analyseur utilisé au moment de la recherche. Mêmes valeurs valides que pour |
Identique à |
Analyseurs intégrés
standard (par défaut), jieba (recommandé pour le chinois, fonctionne mieux que chinese), stop, IK, pattern, whitespace, simple, keyword, chinese, french, dutch, russian.
Pour plus de détails, consultez la section Analyseurs intégrés.
Paramètres d'index
L'objet settings facultatif prend en charge les champs suivants :
analysis
Définit des analyseurs personnalisés. Pour plus de détails, consultez la section Analyseurs personnalisés.
index
Configure des algorithmes de similarité personnalisés. Utilisez cette option pour personnaliser les paramètres Okapi BM25 :
|
Paramètre |
Description |
Par défaut |
Valeurs valides |
|
|
Contrôle l'impact de la fréquence des termes sur le score. Des valeurs plus élevées augmentent cet effet. |
|
Supérieur à |
|
|
Contrôle l'impact de la longueur du document sur le score. Des valeurs plus élevées augmentent cet effet. |
|
|
Exemple :
TFT.CREATEINDEX idx:products '{"mappings":{"properties":{"name":{"type":"keyword","similarity":"my_bm25"}}},"settings":{"index":{"similarity":{"my_bm25":{"type":"BM25","k1":1.0,"b":1.0}}}}}'
queries_cache
Configure le cache des résultats de requête. Par défaut, le cache stocke jusqu'à 10 000 résultats sans limite de mémoire. Lorsqu'il est plein, les résultats sont évincés selon l'algorithme Least Recently Used (LRU).
|
Paramètre |
Type |
Description |
Par défaut |
|
|
STRING |
Mémoire maximale pour tous les caches de requête. Prend en charge les unités |
Aucune limite |
|
|
INTEGER |
Durée de vie (Time to Live) des résultats mis en cache, en secondes. |
|
Exemple :
"settings": {"queries_cache": {"size": "100mb", "ttl": 3}}
queries_cacheest un paramètre au niveau du nœud. Sa configuration sur un index affecte tous les autres index du même processus. Utilisez la même configurationqueries_cachesur tous les index.
compress_doc
Configure la compression transparente des documents. L'activation de la compression augmente la consommation de CPU et la latence en lecture/écriture. Activez cette option uniquement lorsque l'index est volumineux (de l'ordre du kilooctet ou plus) et que le coût de stockage est la préoccupation principale.
|
Paramètre |
Type |
Description |
Par défaut |
|
|
STRING |
Seuil de compression. Les documents ne sont compressés que lorsqu'ils atteignent cette taille. Prend en charge les unités |
|
|
|
BOOLEAN |
Indique s'il faut activer la compression. |
|
Exemple :
"settings": {"compress_doc": {"size": "1kb", "enable": true}}
La compression s'applique uniquement aux documents écrits ou mis à jour après l'activation du paramètre avec TFT.UPDATEINDEX. Les documents existants ne sont pas compressés rétroactivement.
Valeur de retour
En cas de succès :
OKEn cas d'échec : Un message d'erreur
Exemple
TFT.CREATEINDEX idx:product '{"mappings":{"_source":{"enabled":true},"properties":{"product_id":{"type":"keyword","ignore_above":128},"product_name":{"type":"text"},"product_title":{"type":"text","analyzer":"jieba"},"price":{"type":"double"}}}}'
OK
Voir aussi : TFT.UPDATEINDEX, TFT.GETINDEX
TFT.UPDATEINDEX
Ajoute de nouveaux champs au mappage d'un index ou modifie les paramètres de l'index.
Syntaxe
TFT.UPDATEINDEX index mappings [settings]
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
mappings |
Yes |
Nouveaux champs |
|
settings |
No |
Paramètres de l'index modifiés. Seuls |
Pour connaître la syntaxe complète des paramètres mappings et settings, consultez la rubrique TFT.CREATEINDEX.
Valeur de retour
En cas de succès :
OKEn cas d'échec : un message d'erreur
Exemple
TFT.UPDATEINDEX idx:product '{"mappings":{"properties":{"product_group":{"type":"text","analyzer":"chinese"}}}}'
OK
Voir aussi : TFT.CREATEINDEX, TFT.GETINDEX
TFT.GETINDEX
Récupère le mappage et les paramètres d'un index.
Syntaxe
TFT.GETINDEX index
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
Valeur de retour
En cas de succès : le contenu du mappage de l'index au format JSON
En cas d'échec : un message d'erreur
Exemple
TFT.GETINDEX idx:product
{"idx:product0310":{"mappings":{"_source":{"enabled":true,"excludes":[],"includes":["product_id"]},"dynamic":"false","properties":{"price":{"boost":1.0,"enabled":true,"ignore_above":-1,"index":true,"similarity":"classic","type":"double"},"product_id":{"boost":1.0,"enabled":true,"ignore_above":128,"index":true,"similarity":"classic","type":"keyword"},"product_name":{"boost":1.0,"enabled":true,"ignore_above":-1,"index":true,"similarity":"classic","type":"text"},"product_title":{"analyzer":"chinese","boost":1.0,"enabled":true,"ignore_above":-1,"index":true,"similarity":"classic","type":"text"}}}}}
Voir aussi : TFT.CREATEINDEX, TFT.UPDATEINDEX
TFT.ADDDOC
Ajoute un seul document à un index.
Syntaxe
TFT.ADDDOC index document [WITH_ID doc_id]
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
document |
Yes |
Document JSON. Les valeurs des champs doivent correspondre aux types de données définis dans le mappage. |
|
|
No |
ID de document personnalisé (chaîne). Si ce paramètre est omis, un ID est généré automatiquement. Si l'ID spécifié existe déjà, le document existant est écrasé. |
Si_sourceest configuré avecincludes, seuls les champs répertoriés dansincludessont stockés lors de l'ajout ou de la mise à jour d'un document.
Valeur de retour
En cas de succès : un objet JSON contenant l'ID du document, par exemple
{"_id":"00001"}En cas d'échec : un message d'erreur
Exemples
Ajoutez un document avec un ID personnalisé :
TFT.ADDDOC idx:product '{"product_id":"product test"}' WITH_ID 00001
{"_id":"00001"}
Ajoutez un document avec un champ de type tableau :
TFT.ADDDOC idx:product '{"product_id":["an","2","3df"]}' WITH_ID 00001
Voir aussi : TFT.MADDDOC, TFT.UPDATEDOCFIELD, TFT.DELDOC
TFT.MADDDOC
Ajoute plusieurs documents à un index en une seule opération atomique. Si un document présente un format non valide, aucun des documents n'est ajouté.
Syntaxe
TFT.MADDDOC index document doc_id [document1 doc_id1] ...
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
document |
Yes |
Document JSON. Les valeurs des champs doivent correspondre aux types de données définis dans le mappage. |
|
doc_id |
Yes |
ID du document (chaîne). |
Si_sourceest configuré avecincludes, seuls les champs répertoriés dansincludessont stockés lors de l'ajout ou de la mise à jour d'un document.
Valeur de retour
En cas de succès :
OKEn cas d'échec : un message d'erreur
Exemple
TFT.MADDDOC idx:product '{"product_id":"test1"}' 00011 '{"product_id":"test2"}' 00012
OK
Voir aussi : TFT.ADDDOC, TFT.DELDOC
TFT.UPDATEDOCFIELD
Met à jour des champs spécifiques dans un document. Si le document n'existe pas, il est créé (équivalent à TFT.ADDDOC). Si un champ n'existe pas, il est ajouté.
Syntaxe
TFT.UPDATEDOCFIELD index doc_id document
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
doc_id |
Yes |
ID du document à mettre à jour. |
|
document |
Yes |
Objet JSON contenant les champs à mettre à jour. Les champs indexés doivent correspondre aux types de données définis dans le mappage. Les champs non indexés peuvent être de n'importe quel type. |
Si_sourceest configuré avecincludes, seuls les champs répertoriés dansincludessont stockés lors de l'ajout ou de la mise à jour d'un document.
Valeur de retour
En cas de succès :
OKEn cas d'échec : un message d'erreur
Exemple
TFT.UPDATEDOCFIELD idx:product 00011 '{"product_id":"test8","product_group":"BOOK"}'
OK
Voir aussi : TFT.ADDDOC, TFT.DELDOCFIELD
TFT.DELDOCFIELD
Supprime un ou plusieurs champs d'un document. Si le champ est indexé, son entrée d'index est également supprimée.
Syntaxe
TFT.DELDOCFIELD index doc_id field [field1 field2 ...]
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
doc_id |
Yes |
ID du document. |
|
field |
Yes |
Un ou plusieurs noms de champs à supprimer. |
L'opération échoue si le champ spécifié n'existe pas dans le document (par exemple, un champ filtré par _source).
Valeur de retour
En cas de succès : le nombre de champs supprimés (entier)
En cas d'échec : un message d'erreur
Exemple
TFT.DELDOCFIELD idx:product 00011 product_group
(integer) 1
Voir aussi : TFT.UPDATEDOCFIELD
TFT.INCRLONGDOCFIELD
Incrémente un champ entier dans un document. Le champ doit être de type LONG ou INTEGER. Le type de données ARRAY n'est pas pris en charge.
Syntaxe
TFT.INCRLONGDOCFIELD index doc_id field increment
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
doc_id |
Yes |
ID du document. |
|
field |
Yes |
Champ à incrémenter. Doit être de type |
|
increment |
Yes |
Valeur d'incrémentation. Peut être un entier positif ou négatif. |
Si le document n'existe pas, il est créé automatiquement avec le champ initialisé à0avant l'application de l'incrémentation. L'opération échoue si le champ n'existe pas dans le document (par exemple, un champ filtré par_source).
Valeur de retour
En cas de succès : la valeur mise à jour du champ (entier)
En cas d'échec : un message d'erreur
Exemple
TFT.INCRLONGDOCFIELD idx:product 00011 stock 100
(integer)100
Voir aussi : TFT.INCRFLOATDOCFIELD, TFT.UPDATEDOCFIELD
TFT.INCRFLOATDOCFIELD
Incrémente un champ à virgule flottante dans un document. Le champ doit être de type DOUBLE. Le type de données ARRAY n'est pas pris en charge.
Syntaxe
TFT.INCRFLOATDOCFIELD index doc_id field increment
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
doc_id |
Yes |
ID du document. |
|
field |
Yes |
Champ à incrémenter. Doit être de type |
|
increment |
Yes |
Valeur d'incrémentation. Peut être un nombre à virgule flottante positif ou négatif. |
Si le document n'existe pas, il est créé automatiquement avec le champ initialisé à0avant l'application de l'incrémentation. L'opération échoue si le champ n'existe pas dans le document (par exemple, un champ filtré par_source).
Valeur de retour
En cas de succès : la valeur mise à jour du champ (chaîne)
En cas d'échec : un message d'erreur
Exemple
TFT.INCRFLOATDOCFIELD idx:product 00011 stock 299.6
"299.6"
Voir aussi : TFT.INCRLONGDOCFIELD, TFT.UPDATEDOCFIELD
TFT.GETDOC
Récupère un document par son ID.
Syntaxe
TFT.GETDOC index doc_id
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
doc_id |
Yes |
ID du document. |
Valeur de retour
En cas de succès : un objet JSON contenant l'ID et le contenu du document
En cas d'échec : un message d'erreur
Exemple
TFT.GETDOC idx:product 00011
{"_id":"00011","_source":{"product_id":"test8"}}
Voir aussi : TFT.EXISTS, TFT.SEARCH
TFT.EXISTS
Vérifie si un document existe dans un index.
Syntaxe
TFT.EXISTS index doc_id
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
|
doc_id |
Yes |
ID du document. |
Valeur de retour
1si le document existe0si l'index ou le document n'existe pasEn cas d'échec : un message d'erreur
Exemple
TFT.EXISTS idx:product 00011
(integer) 1
Voir aussi : TFT.GETDOC, TFT.DOCNUM
TFT.DOCNUM
Obtient le nombre de documents dans un index.
Syntaxe
TFT.DOCNUM index
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
Nom de l'index. |
Valeur de retour
En cas de succès : le nombre de documents (entier)
En cas d'échec : un message d'erreur
Exemple
TFT.DOCNUM idx:product
(integer) 3
Voir aussi : TFT.EXISTS, TFT.SCANDOCID
TFT.SCANDOCID
Parcourt les ID de document d'un index à l'aide d'un curseur, de manière similaire à la commande Redis SCAN.
Syntaxe
TFT.SCANDOCID index cursor [MATCH *value*] [COUNT count]
Paramètres
|
Paramètre |
Obligatoire |
Description |
|
index |
Oui |
Nom de l'index. |
|
cursor |
Oui |
Position du curseur. Utilisez |
|
|
Non |
Motif de type glob permettant de filtrer les ID de document. Exemple : |
|
|
Non |
Nombre maximal d'éléments à renvoyer par analyse. Valeur par défaut : |
Valeur de retour
Un tableau à deux éléments :
Le curseur pour l'itération suivante. La valeur
0indique que l'analyse est terminée.Un tableau contenant les ID de document.
Exemple
TFT.SCANDOCID idx:product 0 COUNT 3
1) "0"
2) 1) "00001"
2) "00011"
3) "00012"
Voir aussi : TFT.DOCNUM, TFT.GETDOC
TFT.DELDOC
Supprime un ou plusieurs documents d'un index en fonction de leur ID.
Syntaxe
TFT.DELDOC index doc_id [doc_id] ...
Paramètres
|
Paramètre |
Obligatoire |
Description |
|
index |
Oui |
Nom de l'index. |
|
doc_id |
Oui |
Un ou plusieurs ID de document à supprimer. |
Valeur de retour
En cas de succès : nombre de documents effectivement supprimés (chaîne de caractères). Les ID inexistants sont ignorés.
En cas d'échec : message d'erreur.
Exemple
TFT.DELDOC idx:product 00011 00014
"1" # Document 00014 does not exist, so only document 00011 is deleted.
Voir aussi : TFT.DELALL, TFT.ADDDOC
TFT.DELALL
Supprime tous les documents d'un index tout en conservant l'index et son mappage.
Syntaxe
TFT.DELALL index
Paramètres
|
Paramètre |
Obligatoire |
Description |
|
index |
Oui |
Nom de l'index. |
Valeur de retour
En cas de succès :
OKEn cas d'échec : message d'erreur.
Exemple
TFT.DELALL idx:product
OK
Voir aussi : TFT.DELDOC, DEL
TFT.ANALYZER
Teste la façon dont un analyseur tokenize un texte donné.
Syntaxe
TFT.ANALYZER analyzer_name text [INDEX index_name] [SHOW_TIME]
Paramètres
|
Paramètre |
Obligatoire |
Description |
|
analyzer_name |
Oui |
Nom d'un analyseur intégré ou personnalisé. |
|
text |
Oui |
Texte à tokeniser. Doit être encodé en UTF-8. |
|
|
Conditionnel |
Index contenant la définition de l'analyseur. Requis lors de l'utilisation d'un analyseur personnalisé ou d'un analyseur intégré avec des mots vides ou des dictionnaires modifiés. |
|
|
Non |
Inclut la durée de tokenisation dans la sortie, exprimée en microsecondes. La première exécution avec un dictionnaire volumineux (par exemple, Jieba, IK) peut prendre plusieurs secondes en raison du chargement du dictionnaire. |
Valeur de retour
En cas de succès : objet JSON contenant les détails des tokens.
En cas d'échec : message d'erreur.
Exemple
TFT.ANALYZER standard "Tair is a nosql database"
{
"tokens": [
{"token": "Tair", "start_offset": 0, "end_offset": 4, "position": 0},
{"token": "nosql", "start_offset": 10, "end_offset": 15, "position": 3},
{"token": "database", "start_offset": 16, "end_offset": 24, "position": 4}
]
}
DEL (Redis natif)
Utilisez la commande native Redis DEL pour supprimer une ou plusieurs clés TairSearch (index).
DEL key [key ...]
Pour plus de détails, consultez la documentation de référence de la commande DEL.
TFT.SEARCH
Recherche des documents dans un index à l'aide du langage DSL de requête.
Syntaxe
TFT.SEARCH index query
Paramètres
|
Paramètre |
Obligatoire |
Description |
|
index |
Oui |
Nom de l'index. |
|
query |
Oui |
Instruction JSON au format Query DSL. Consultez les sections ci-dessous pour la syntaxe complète. |
La syntaxe de requête est similaire à celle du langage DSL de requête Elasticsearch.
Valeur de retour
En cas de succès, un objet JSON contenant les résultats de la recherche :
{
"hits": {
"hits": [
{"_id": "...", "_index": "...", "_score": 1.0, "_source": {...}}
],
"max_score": 1.0,
"total": {
"relation": "eq",
"value": 3
}
}
}
Le champ total.relation indique la relation entre le compte et la valeur total.value :
"eq": le compte est exact."gte": le compte est au moins égal à cette valeur (lorsquetrack_total_hitsest défini surfalse).
Exemple
TFT.SEARCH idx:product '{"sort":[{"price":{"order":"desc"}}]}'
{"hits":{"hits":[{"_id":"fruits_3","_index":"idx:product","_score":1.0,"_source":{"product_id":"fruits_3","product_name":"orange","price":30.2,"stock":3000}},{"_id":"fruits_2","_index":"idx:product","_score":1.0,"_source":{"product_id":"fruits_2","product_name":"banana","price":24.0,"stock":2000}},{"_id":"fruits_1","_index":"idx:product","_score":1.0,"_source":{"product_id":"fruits_1","product_name":"apple","price":19.5,"stock":1000}}],"max_score":1.0,"total":{"relation":"eq","value":3}}}
Voir aussi : TFT.MSEARCH, TFT.EXPLAINCOST, TFT.EXPLAINSCORE
Types de requêtes
Le champ query du langage DSL de requête prend en charge les types de requêtes suivants.
Tri
Utilisez le champ sort pour contrôler l'ordre des résultats. Le type de données ARRAY n'est pas pris en charge pour le tri.
|
Valeur |
description |
|
|
Tri par score de pertinence dans l'ordre décroissant. |
|
|
Tri par ID de document dans l'ordre croissant. |
|
nom_champ |
Tri par un champ spécifique dans l'ordre croissant. Le champ doit être indexé ( |
Pour un tri sur plusieurs champs, utilisez un tableau. Contrôlez la direction du tri avec order ("desc" ou "asc") :
{"sort": [{"price": {"order": "desc"}}, {"_doc": {"order": "desc"}}]}
Filtrage source
Utilisez le champ _source pour contrôler les champs de document affichés dans les résultats :
{"_source": {"includes": ["f0"]}}
Prend en charge à la fois includes et excludes avec des motifs génériques.
Pagination
|
Paramètre |
type |
description |
Par défaut |
|
|
INTEGER |
Décalage basé sur zéro du premier résultat à renvoyer. |
|
|
|
INTEGER |
Nombre maximal de résultats à renvoyer. Valeurs valides : |
|
L'utilisation conjointe defrometsizepermet la pagination. Les performances de la requête diminuent à mesure quefromaugmente.
track_total_hits
Contrôle si tous les documents correspondants doivent être comptés pour les requêtes term, terms ou match (les requêtes composées sont également prises en charge, mais la correspondance floue dans match est désactivée).
|
Valeur |
Comportement |
|
|
Renvoie uniquement les 100 premiers documents triés par score. |
|
|
Compte tous les documents correspondants. |
La définition de track_total_hits sur true avec un grand nombre de documents correspondants peut ralentir les requêtes. Utilisez cette option avec précaution.
TFT.MSEARCH
Effectue une recherche sur plusieurs index partageant des mappings et des paramètres identiques, puis agrège et renvoie les résultats combinés.
Syntaxe
TFT.MSEARCH index_count index [index1] ... query
Paramètres
|
Paramètre |
Obligatoire |
description |
|
index_count |
Oui |
Nombre d'index à rechercher. Valeurs valides : |
|
index |
Oui |
Un ou plusieurs noms d'index. Tous les index doivent avoir des |
|
query |
Oui |
Une instruction JSON Query DSL. Prend en charge |
TFT.MSEARCHne prend pas en charge le paramètrefrom. Utilisez plutôt la pagination basée sur un curseur (voir ci-dessous).
Pagination basée sur un curseur
Utilisez conjointement size, reply_with_keys_cursor et keys_cursor pour la pagination :
|
Paramètre |
type |
description |
Par défaut |
|
|
INTEGER |
Nombre de résultats à renvoyer par page. |
|
|
|
BOOLEAN |
Inclure les positions du curseur dans la réponse. |
|
|
|
OBJECT |
Positions du curseur de la requête précédente. Utilisez |
|
Fonctionnement :
Première requête : Définissez
reply_with_keys_cursorsurtrueet omettezkeys_cursor(ou définissez-le sur0). Tair récupèresizedocuments de chaque index, puis rassemble, note, trie et agrège les résultats combinés, en renvoyant lessizemeilleurs documents. La réponse inclut les positionskeys_cursorpour chaque index.Requête suivante : Transmettez le
keys_cursorrenvoyé dans la réponse précédente. Tair poursuit la récupération à partir des positions du curseur dans chaque index.
Comportement d'agrégation
TFT.MSEARCH agrège les ensembles de résultats enfants de chaque index plutôt que d'agréger l'ensemble de données combiné :
Rate et sort : Note et trie les ensembles de résultats enfants.
sum, max, min, avg, value_count : Agrège les ensembles de résultats enfants.
sum_of_squares, variance, std_deviation : Fait la moyenne des ensembles de résultats enfants.
Terms aggregation et filter aggregation : Agrège séparément les ensembles de résultats enfants.
Valeur de retour
En cas de succès, un objet JSON similaire à la sortie de TFT.SEARCH, plus un champ aux_info :
{
"aux_info": {
"index_crc64": 15096806844241479487,
"keys_cursor": {"key0": 2, "key1": 5, "key2": 3},
"field_type": {"f0": "long"}
}
}
|
Champ |
description |
|
|
Hachage CRC-64 des mappings et des paramètres. Peut être ignoré pour les requêtes métier. |
|
|
Positions du curseur pour la prochaine requête paginée. Inclus uniquement lorsque |
|
|
types de données des champs triés. Inclus uniquement lors du tri par un champ d'index. |
Exemple
Configurez trois index avec le même mapping :
TFT.CREATEINDEX key0 '{"mappings":{"properties":{"f0":{"type":"long"}}}}'
TFT.CREATEINDEX key1 '{"mappings":{"properties":{"f0":{"type":"long"}}}}'
TFT.CREATEINDEX key2 '{"mappings":{"properties":{"f0":{"type":"long"}}}}'
TFT.ADDDOC key0 '{"f0":120}'
TFT.ADDDOC key0 '{"f0":130}'
TFT.ADDDOC key1 '{"f0":140}'
TFT.ADDDOC key1 '{"f0":150}'
TFT.ADDDOC key2 '{"f0":160}'
TFT.ADDDOC key2 '{"f0":170}'
Première page :
TFT.MSEARCH 3 key0 key1 key2 '{"size":2,"query":{"range":{"f0":{"gt":120,"lte":170}}},"sort":[{"f0":{"order":"desc"}}],"reply_with_keys_cursor":true}'
{"hits":{"hits":[{"_id":"16625439765504840","_index":"key2","_score":1.0,"_source":{"f0":170}},{"_id":"16625439741096630","_index":"key2","_score":1.0,"_source":{"f0":160}}],"max_score":1.0,"total":{"relation":"eq","value":5}},"aux_info":{"index_crc64":10084399559244916810,"keys_cursor":{"key0":0,"key1":0,"key2":2}}}
Deuxième page (transmettez le keys_cursor de la réponse précédente) :
TFT.MSEARCH 3 key0 key1 key2 '{"size":2,"query":{"range":{"f0":{"gt":120,"lte":170}}},"sort":[{"f0":{"order":"desc"}}],"reply_with_keys_cursor":true,"keys_cursor":{"key0":0,"key1":0,"key2":2}}'
{"hits":{"hits":[{"_id":"16625439652681160","_index":"key1","_score":1.0,"_source":{"f0":150}},{"_id":"16625439624704580","_index":"key1","_score":1.0,"_source":{"f0":140}}],"max_score":1.0,"total":{"relation":"eq","value":5}},"aux_info":{"index_crc64":10084399559244916810,"keys_cursor":{"key0":0,"key1":2,"key2":2}}}
Voir aussi : TFT.SEARCH
TFT.EXPLAINCOST
Récupère le détail des temps d'exécution d'une requête.
Syntaxe
TFT.EXPLAINCOST index query
Paramètres
|
Paramètre |
Obligatoire |
description |
|
index |
Oui |
Nom de l'index. |
|
query |
Oui |
Une instruction Query DSL (même syntaxe que |
Valeur de retour
Un objet JSON contenant les sections suivantes :
|
Section |
description |
|
|
Temps d'exécution de la requête en microsecondes ( |
|
|
Temps d'agrégation en microsecondes. Omis si aucune agrégation n'est spécifiée. |
|
|
Temps de collecte et de tri des résultats en microsecondes, ainsi que le type de collecteur : |
Exemple
TFT.EXPLAINCOST idx:product '{"sort":[{"price":{"order":"desc"}}]}'
{
"QUERY_COST": {
"query": "MATCHALL_QUERY",
"doc_num": 1,
"time_cost_us": 2
},
"COLLECTOR_COST": {
"collector_type": "CustomSortCollector",
"time_cost_us": 20
}
}
Voir aussi : TFT.SEARCH, TFT.EXPLAINSCORE
TFT.EXPLAINSCORE
Récupère des détails précis sur la notation des résultats de recherche, montrant comment les scores des documents sont calculés.
Disponible uniquement pour les instances basées sur DRAM compatibles avec Redis 6.0 ou version ultérieure.
Syntaxe
TFT.EXPLAINSCORE index query [doc_id] ...
Paramètres
|
Paramètre |
Obligatoire |
description |
|
index |
Oui |
Nom de l'index. |
|
query |
Oui |
Une instruction Query DSL (même syntaxe que |
|
doc_id |
Non |
Un ou plusieurs ID de document. Lorsqu'ils sont spécifiés, seuls ces documents sont inclus dans la sortie. |
Valeur de retour
Le même ensemble de résultats que TFT.SEARCH, plus un objet _explanation pour chaque document contenant :
|
Champ |
description |
|
|
Score du document. |
|
|
Formule utilisée pour le calcul du score. |
|
|
Champ du document correspondant aux termes de la requête. |
|
|
Terme de la requête trouvé dans le document. |
|
|
Poids de notation appliqué à cette clause de requête. |
|
|
Métadonnées et processus de notation étape par étape. |
Exemple
TFT.EXPLAINSCORE today_shares '{"query":{"wildcard":{"shares_name":{"value":"*BY"}}}}'
{
"hits": {
"hits": [
{
"_id": "17036492095306830",
"_index": "today_shares",
"_score": 1.0,
"_source": {
"shares_name": "YBY",
"logictime": 14300410,
"purchase_type": 1,
"purchase_price": 11.1,
"purchase_count": 100,
"investor": "Mila"
},
"_explanation": {
"score": 1.0,
"description": "score, computed as query_boost",
"field": "shares_name",
"term": "*BY",
"query_boost": 1.0
}
}
],
"max_score": 1.0,
"total": {"relation": "eq", "value": 1}
}
}
Voir aussi : TFT.SEARCH, TFT.EXPLAINCOST
Commandes de saisie semi-automatique
TFT.ADDSUG
Ajoute une ou plusieurs entrées de texte de saisie semi-automatique avec des poids associés.
Syntaxe
TFT.ADDSUG index text weight [text weight] ...
Paramètres
|
Paramètre |
Obligatoire |
description |
|
index |
Oui |
Nom de l'index. |
|
text |
Oui |
Entrée de texte de saisie semi-automatique. |
|
weight |
Oui |
Poids de notation (entier positif). Les poids plus élevés sont classés plus haut dans les résultats. |
Valeur de retour
En cas de succès : Nombre d'entrées de texte ajoutées (entier)
En cas d'échec : Message d'erreur
Exemple
TFT.ADDSUG idx:redis 'redis is a memory database' 3 'redis cluster' 10
(integer) 2
Voir aussi : TFT.GETSUG, TFT.DELSUG, TFT.SUGNUM
TFT.DELSUG
Supprime une ou plusieurs entrées de texte de saisie semi-automatique d'un index.
Syntaxe
TFT.DELSUG index text [text] ...
Paramètres
|
Paramètre |
Obligatoire |
description |
|
index |
Oui |
Nom de l'index. |
|
text |
Oui |
Entrée de texte exacte à supprimer. Doit correspondre exactement et complètement. |
Valeur de retour
En cas de succès : Nombre d'entrées de texte supprimées (entier)
En cas d'échec : Message d'erreur
Exemple
TFT.DELSUG idx:redis 'redis is a memory database' 'redis cluster'
(integer) 2
Voir aussi : TFT.ADDSUG, TFT.SUGNUM
TFT.SUGNUM
Récupère le nombre d'entrées de saisie semi-automatique dans un index.
Syntaxe
TFT.SUGNUM index
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
The name of the index. |
Valeur de retour
En cas de succès : le nombre d'entrées (entier)
En cas d'échec : un message d'erreur
Exemple
TFT.SUGNUM idx:redis
(integer) 3
Voir aussi : TFT.ADDSUG, TFT.GETSUG
TFT.GETSUG
Récupère les suggestions de saisie semi-automatique correspondant à un préfixe. Les résultats sont renvoyés par ordre décroissant de poids.
Syntaxe
TFT.GETSUG index prefix [MAX_COUNT count] [FUZZY]
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
The name of the index. |
|
prefix |
Yes |
The prefix to match. |
|
|
No |
Maximum number of entries to return. Valid values: |
|
|
No |
Enable fuzzy matching. |
Valeur de retour
En cas de succès : une liste des entrées de texte correspondantes pour la saisie semi-automatique
En cas d'échec : un message d'erreur
Exemple
TFT.GETSUG idx:redis res MAX_COUNT 2 FUZZY
1) "redis cluster"
2) "redis lock"
Voir aussi : TFT.ADDSUG, TFT.GETALLSUGS
TFT.GETALLSUGS
Récupère toutes les entrées de texte de saisie semi-automatique dans un index.
Syntaxe
TFT.GETALLSUGS index
Paramètres
|
Parameter |
Required |
Description |
|
index |
Yes |
The name of the index. |
Valeur de retour
En cas de succès : une liste de toutes les entrées de texte de saisie semi-automatique
En cas d'échec : un message d'erreur
Exemple
TFT.GETALLSUGS idx:redis
1) "redis cluster"
2) "redis lock"
3) "redis is a memory database"
Voir aussi : TFT.GETSUG, TFT.ADDSUG
Agrégations
Ajoutez une clause aggs (ou aggregations) à une requête TFT.SEARCH pour effectuer des agrégations sur l'ensemble des résultats.
Utilisation de base
Spécifiez un nom d'agrégation personnalisé, un type d'agrégation et un champ field sur lequel appliquer l'agrégation :
TFT.SEARCH shares '{"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Sum":{"sum":{"field":"purchase_price"}}}}'
La réponse inclut à la fois les résultats de recherche issus de la clause query et les résultats d'agrégation issus de la clause aggs :
{"hits":{"hits":[{"_id":"16581351808123930","_index":"today_shares0718","_score":1.0,"_source":{"shares_name":"XAX","logictime":14300210,"purchase_type":1,"purchase_price":101.1,"purchase_count":100,"investor":"Jay"}},{"_id":"16581351809626430","_index":"today_shares0718","_score":1.0,"_source":{"shares_name":"XAX","logictime":14300310,"purchase_type":1,"purchase_price":111.1,"purchase_count":100,"investor":"Jay"}}],"max_score":1.0,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Sum":{"value":212.2}}}
Ajoutez "size": 0 à la requête pour renvoyer uniquement les résultats d'agrégation sans les documents.
Agrégation de métriques
Les agrégations de métriques effectuent des calculs numériques sur des champs numériques (integer, double, etc.) et ne prennent pas en charge les sous-agrégations imbriquées.
|
Metric |
Description |
Supported field types |
|
|
Sum of field values |
Numeric |
|
|
Maximum value |
Numeric |
|
|
Minimum value |
Numeric |
|
|
Average value |
Numeric |
|
|
Sum of squared values |
Numeric |
|
|
Statistical variance |
Numeric |
|
|
Standard deviation |
Numeric |
|
|
Count of values (without deduplication) |
Numeric, |
|
|
All of the above metrics in a single response |
Numeric |
Seule l'agrégationvalue_countprend en charge les champskeyword. Toutes les autres métriques nécessitent des champs numériques.
Sortie : une valeur DOUBLE calculée à partir du champ spécifié.
Agrégation par termes
Compte les valeurs dédupliquées dans un champ keyword . Prend en charge les sous-agrégations imbriquées.
|
Parameter |
Description |
Default |
|
|
The aggregation field. Only |
Required |
|
|
Number of buckets to return. Valid values: |
|
|
|
Sort order. |
|
|
|
Minimum document count for a bucket to be included in the results. |
|
|
|
A regex pattern or exact value that bucket keys must match. For string fields, regex matching is supported. For array fields, exact matching is required. |
-- |
|
|
A regex pattern or exact value that bucket keys must not match. If both |
-- |
Sortie : un objet JSON contenant des compartiments buckets . Chaque compartiment contient une clé key (la valeur du champ) et un nombre de documents doc_count :
{
"aggregations": {
"Per_Investor_Freq": {
"buckets": [
{"doc_count": 2, "key": "Jay"},
{"doc_count": 1, "key": "Mila"}
]
}
}
}
Exemple :
{"aggs": {"Per_Investor_Freq": {"terms": {"field": "investor"}}}}
Agrégation par filtre
Filtre les résultats de requête avec une instruction de requête et compte les documents correspondants. Prend en charge les sous-agrégations imbriquées.
Sortie : le nombre de documents (doc_count ) correspondant à la condition de filtre.
Exemples d'agrégation
Les exemples suivants utilisent un jeu de données sur les transactions boursières.
Étape 1 : Créez l'index
TFT.CREATEINDEX today_shares '{"mappings":{"properties":{"shares_name":{"type":"keyword"},"logictime":{"type":"long"},"purchase_type":{"type":"integer"},"purchase_price":{"type":"double"},"purchase_count":{"type":"long"},"investor":{"type":"keyword"}}}}'
Étape 2 : Ajoutez des documents
TFT.ADDDOC today_shares '{"shares_name":"XAX","logictime":14300210,"purchase_type":1,"purchase_price":101.1,"purchase_count":100,"investor":"Jay"}'
TFT.ADDDOC today_shares '{"shares_name":"XAX","logictime":14300310,"purchase_type":1,"purchase_price":111.1,"purchase_count":100,"investor":"Jay"}'
TFT.ADDDOC today_shares '{"shares_name":"YBY","logictime":14300410,"purchase_type":1,"purchase_price":11.1,"purchase_count":100,"investor":"Mila"}'
Étape 3 : Exécutez les requêtes
sum -- Montant total des achats pour un investisseur
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Sum":{"sum":{"field":"purchase_price"}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Sum":{"value":212.2}}}
max -- Prix d'achat le plus élevé pour un investisseur
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Max":{"max":{"field":"purchase_price"}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Max":{"value":111.1}}}
avg -- Prix d'achat moyen pour un investisseur
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Avg":{"avg":{"field":"purchase_price"}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Avg":{"value":106.1}}}
std_deviation -- Écart-type des prix d'achat
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Std_Deviation":{"std_deviation":{"field":"purchase_price"}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Std_Deviation":{"value":5.0}}}
extended_stats -- Toutes les statistiques en une seule fois
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"investor":"Jay"}},"aggs":{"Jay_Extended_Stats":{"extended_stats":{"field":"purchase_price"}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":2}},"aggregations":{"Jay_Extended_Stats":{"count":2,"sum":212.2,"max":111.1,"min":101.1,"avg":106.1,"sum_of_squares":10221.21,"variance":25.0,"std_deviation":5.0}}}
terms -- Investisseurs ayant effectué au moins deux transactions
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"purchase_type":1}},"aggs":{"Per_Investor_Freq":{"terms":{"field":"investor","min_doc_count":2,"order":{"_key":"desc"}}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":3}},"aggregations":{"Per_Investor_Freq":{"buckets":[{"key":"Jay","doc_count":2}]}}}
Agrégation par termes imbriquée — Nombre de transactions par action avec prix moyen
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"purchase_type":1}},"aggs":{"Per_Investor_Freq":{"terms":{"field":"shares_name","include":"[A-Z]+","exclude":["XAX"]},"aggs":{"Price_Avg":{"avg":{"field":"purchase_price"}}}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":3}},"aggregations":{"Per_Investor_Freq":{"buckets":[{"key":"YBY","doc_count":1,"Price_Avg":{"value":11.1}}]}}}
Agrégation par filtre imbriquée — Filtrage par investisseur avec statistiques étendues
TFT.SEARCH today_shares '{"size":0,"query":{"term":{"purchase_type":1}},"aggs":{"Jay_BuyIn_Filter":{"filter":{"term":{"investor":"Jay"}},"aggs":{"Jay_BuyIn_Quatation":{"extended_stats":{"field":"purchase_price"}}}}}}'
{"hits":{"hits":[],"max_score":null,"total":{"relation":"eq","value":3}},"aggregations":{"Jay_BuyIn_Filter":{"doc_count":2,"Jay_BuyIn_Quatation":{"count":2,"sum":212.2,"max":111.1,"min":101.1,"avg":106.1,"sum_of_squares":10221.21,"variance":25.0,"std_deviation":5.0}}}}