La codifica UTF8 è più lunga della lunghezza massima 32766

Ho aggiornato il mio cluster Elasticsearch da 1.1 a 1.2 e ho errori durante l’indicizzazione di una stringa piuttosto grande.

{ "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 mapping dell’indice:

 { "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" } } } } } 

Ho cercato la documentazione e non ho trovato nulla relativo alla dimensione massima del campo. Secondo la sezione dei tipi di base , non capisco perché dovrei “correggere l’analizzatore” per un campo non not_analyzed .

Quindi stai incontrando un problema con la dimensione massima per un singolo termine. Quando imposti un campo su not_analyzed, lo tratterà come un unico termine. La dimensione massima per un singolo termine nell’indice di Lucene sottostante è 32766 byte, che credo sia codificato in modo rigido.

Le tue due opzioni principali consistono nel cambiare il tipo in binario o continuare a utilizzare la stringa, ma impostare il tipo di indice su “no”.

Se vuoi davvero not_analyzed sulla proprietà perché vuoi fare un filtro esatto, puoi usare "ignore_above": 256

Ecco un esempio di come lo uso in php:

 'mapping' => [ 'type' => 'multi_field', 'path' => 'full', 'fields' => [ '{name}' => [ 'type' => 'string', 'index' => 'analyzed', 'analyzer' => 'standard', ], 'raw' => [ 'type' => 'string', 'index' => 'not_analyzed', 'ignore_above' => 256, ], ], ], 

Nel tuo caso, probabilmente vorrai fare come ti ha detto John Petrone e impostare "index": "no" ma per chiunque abbia trovato questa domanda dopo, come me, cercando su quell’eccezione, le tue opzioni sono:

  • imposta "index": "no"
  • imposta "index": "analyze"
  • imposta "index": "not_analyzed" e "ignore_above": 256

Dipende da se e come vuoi filtrare su quella proprietà.

Esiste un’opzione migliore rispetto a quella pubblicata da John. Perché con quella soluzione non puoi più cercare il valore.

Torna al problema:

Il problema è che per impostazione predefinita i valori dei campi verranno utilizzati come un unico termine (stringa completa). Se quel termine / stringa è più lungo dei 32766 byte, non può essere memorizzato in Lucene.

Le versioni precedenti di Lucene registrano un avviso solo quando i termini sono troppo lunghi (e ignorano il valore). Le versioni più recenti generano un’eccezione. Vedi bugfix: https://issues.apache.org/jira/browse/LUCENE-5472

Soluzione:

L’opzione migliore è definire un analizzatore (personalizzato) sul campo con il valore stringa lungo. L’analizzatore può dividere la stringa lunga in stringhe / termini più piccoli. Ciò risolverà il problema di termini troppo lunghi.

Non dimenticare di aggiungere anche un analizzatore al campo “_all” se stai usando quella funzionalità.

Gli analizzatori possono essere testati con l’API REST. http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-analyze.html

Avevo bisogno di cambiare la parte index della mapping su no invece che su not_analyzed . In questo modo il valore non è indicizzato. Rimane disponibile nel documento restituito (da una ricerca, un ottenere, …) ma non posso interrogarlo.

Un modo per gestire i token che superano il limite di lucene è utilizzare il filtro truncate . Simile a ignore_above per le parole chiave. Per dimostrare, sto usando 5 . Elasticsearch suggerisce di usare ignore_above = 32766/4 = 8191 poiché i caratteri UTF-8 possono occupare al massimo 4 byte. 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" }' 

Produzione:

 { "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 } ] } 

Ho risolto questo problema cambiando il mio analizzatore.

 { "index" : { "analysis" : { "analyzer" : { "standard" : { "tokenizer": "standard", "filter": ["standard", "lowercase", "stop"] } } } } } 

Se stai usando searchkick , aggiorna searchkick a >= 2.2.0 e assicurati di utilizzare searchkick 1.3.4 o successivo.

Questa versione di searchkick imposta ignore_above = 256 di default, quindi non si otterrà questo errore quando UTF> 32766.

Questo è discusso qui .

In Solr v6 + ho cambiato il tipo di campo in text_general e ho risolto il mio problema.

   

Usando logstash per indicizzare quei messaggi lunghi, utilizzo questo filtro per troncare la stringa lunga:

  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 " } } 

Aggiunge un campo message_size in modo che possa ordinare i messaggi più lunghi per dimensione.

Aggiunge anche il tag messaggio lungo a quelli che superano i 32000kb, quindi posso selezionarli facilmente.

Non risolve il problema se intendi indicizzare completamente quei lunghi messaggi, ma se, come me, non li vuoi avere in elasticsearch in primo luogo e vuoi rintracciarli per risolverli, è una soluzione funzionante.

Mi sono imbattuto nello stesso messaggio di errore con il modulo degli allegati API di ricerca di Drupal:

Il documento contiene almeno un termine immenso in field = “saa_saa_file_entity” (la cui codifica UTF8 è più lunga della lunghezza massima di 32766), che sono stati tutti ignorati. Si prega di correggere l’analizzatore per non produrre tali termini.

La modifica del tipo di campo da string a testo Fulltext (in / admin / config / search / search-api / index / elastic_index / fields ) ha risolto il problema per me.