J'ai mis à niveau mon cluster Elasticsearch de 1.1 à 1.2 et j'ai des erreurs lors de l'indexation d'une chaîne assez grosse.
{
"error": "IllegalArgumentException[Document contains at least one immense term in field=\"response_body\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[7b 22 58 48 49 5f 48 6f 74 65 6c 41 76 61 69 6c 52 53 22 3a 7b 22 6d 73 67 56 65 72 73 69]...']",
"status": 500
}
La cartographie de l'index:
{
"template": "partner_requests-*",
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"request": {
"properties": {
"asn_id": { "index": "not_analyzed", "type": "string" },
"search_id": { "index": "not_analyzed", "type": "string" },
"partner": { "index": "not_analyzed", "type": "string" },
"start": { "type": "date" },
"duration": { "type": "float" },
"request_method": { "index": "not_analyzed", "type": "string" },
"request_url": { "index": "not_analyzed", "type": "string" },
"request_body": { "index": "not_analyzed", "type": "string" },
"response_status": { "type": "integer" },
"response_body": { "index": "not_analyzed", "type": "string" }
}
}
}
}
J'ai consulté la documentation et rien trouvé concernant une taille de champ maximale. Selon la section types de noya , je ne comprends pas pourquoi je devrais "corriger l'analyseur" pour un not_analyzed
champ.
Vous rencontrez donc un problème de taille maximale pour un seul mandat. Lorsque vous définissez un champ sur non_analysé, il le traite comme un seul terme. La taille maximale pour un seul terme dans l'index Lucene sous-jacent est de 32 766 octets, ce qui est, je crois, codé en dur.
Vos deux options principales sont de changer le type en binaire ou de continuer à utiliser chaîne, mais de définir le type d'index sur "non".
Si vous voulez vraiment not_analyzed
sur la propriété parce que vous voulez faire un filtrage exact, vous pouvez utiliser "ignore_above": 256
Voici un exemple de comment je l'utilise en php:
'mapping' => [
'type' => 'multi_field',
'path' => 'full',
'fields' => [
'{name}' => [
'type' => 'string',
'index' => 'analyzed',
'analyzer' => 'standard',
],
'raw' => [
'type' => 'string',
'index' => 'not_analyzed',
'ignore_above' => 256,
],
],
],
Dans votre cas, vous voudrez probablement faire ce que John Petrone vous a dit et mettez "index": "no"
mais pour quiconque trouve cette question après, comme moi, recherchant cette exception, vos options sont les suivantes:
"index": "no"
"index": "analyze"
"index": "not_analyzed"
et "ignore_above": 256
Cela dépend si et comment vous voulez filtrer sur cette propriété.
Il y a une meilleure option que celle affichée par John. Parce qu'avec cette solution, vous ne pouvez plus rechercher sur la valeur.
Retour au problème:
Le problème est que, par défaut, les valeurs de champ seront utilisées comme un terme unique (chaîne complète). Si ce terme/cette chaîne est plus long que les 32 766 octets, il ne peut pas être stocké dans Lucene.
Les anciennes versions de Lucene n'enregistrent un avertissement que lorsque les termes sont trop longs (et ignorent la valeur). Les versions les plus récentes génèrent une exception. Voir la correction: https://issues.Apache.org/jira/browse/LUCENE-5472
Solution:
La meilleure option consiste à définir un analyseur (personnalisé) sur le champ avec la valeur de chaîne longue. L'analyseur peut séparer la longue chaîne en chaînes/termes plus petits. Cela résoudra le problème des délais trop longs.
N'oubliez pas d'ajouter également un analyseur au champ "_all" si vous utilisez cette fonctionnalité.
Les analyseurs peuvent être testés avec REST api. http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-analyze.html
J'avais besoin de changer la partie index
du mappage en no
au lieu de not_analyzed
. De cette façon, la valeur n'est pas indexée. Il reste disponible dans le document renvoyé (à partir d'une recherche, d'un get,…) mais je ne peux pas l'interroger.
Une façon de gérer les jetons qui dépassent la limite de lucene consiste à utiliser le filtre truncate
. Semblable à ignore_above
pour les mots-clés. Pour démontrer, j'utilise 5
. Elasticsearch suggère d'utiliser ignore_above = 32766/4 = 8191
puisque les caractères UTF-8 peuvent occuper au plus 4 octets. https://www.elastic.co/guide/en/elasticsearch/reference/6.3/ignore-above.html
curl -H'Content-Type:application/json' localhost:9200/_analyze -d'{
"filter" : [{"type": "truncate", "length": 5}],
"tokenizer": {
"type": "pattern"
},
"text": "This movie \n= AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
}'
Sortie:
{
"tokens": [
{
"token": "This",
"start_offset": 0,
"end_offset": 4,
"type": "Word",
"position": 0
},
{
"token": "movie",
"start_offset": 5,
"end_offset": 10,
"type": "Word",
"position": 1
},
{
"token": "AAAAA",
"start_offset": 14,
"end_offset": 52,
"type": "Word",
"position": 2
}
]
}
Je suis tombé sur le même message d'erreur avec Rechercher les pièces jointes de l'API de Drupal module:
Le document contient au moins un terme immense dans field = "saa_saa_file_entity" (dont le codage UTF8 est plus long que la longueur maximale 32766), qui ont tous été ignorés. S'il vous plaît corriger l'analyseur pour ne pas produire de tels termes.
Changer le type de champs de string
à Fulltext
(dans /admin/config/search/search-api/index/elastic_index/fields ) résolu le problème pour moi.
Si vous utilisez searchkick
, mettez à niveau elasticsearch vers >= 2.2.0
& assurez-vous que vous utilisez searchkick 1.3.4
ou plus tard.
Cette version de searchkick définit ignore_above = 256
_ par défaut, vous n'obtiendrez pas cette erreur si UTF> 32766.
Ceci est discuté ici .
J'ai contourné ce problème en changeant mon analyseur.
{
"index" : {
"analysis" : {
"analyzer" : {
"standard" : {
"tokenizer": "standard",
"filter": ["standard", "lowercase", "stop"]
}
}
}
}
}
À l'aide de logstash pour indexer ces longs messages, j'utilise ce filtre pour tronquer la chaîne longue:
filter {
Ruby {
code => "event.set('message_size',event.get('message').bytesize) if event.get('message')"
}
Ruby {
code => "
if (event.get('message_size'))
event.set('message', event.get('message')[0..9999]) if event.get('message_size') > 32000
event.tag 'long message' if event.get('message_size') > 32000
end
"
}
}
Il ajoute un champ message_size afin que je puisse trier les messages les plus longs par taille.
Il ajoute également la balise message long à ceux qui dépassent 32 000 Ko afin que je puisse les sélectionner facilement.
Cela ne résout pas le problème si vous souhaitez indexer complètement ces longs messages, mais si, comme moi, vous ne souhaitez pas les inclure dans elasticsearch et si vous souhaitez les rechercher pour les résoudre, c'est une solution efficace.
Dans Solr v6 +, j'ai changé le type de champ en text_general et cela a résolu mon problème.
<field name="body" type="string" indexed="true" stored="true" multiValued="false"/>
<field name="id" type="string" multiValued="false" indexed="true" required="true" stored="true"/>