2015-05-06 11 views
7

Ogni esempio che ho visto (ad esempio, ElasticSearch: aggregation on _score field?) per eseguire aggregazioni su o correlato al campo _score sembra richiedere l'utilizzo di script. Con ElasticSearch disattivando lo scripting dinamico per impostazione predefinita per motivi di sicurezza, esiste un modo per farlo senza ricorrere al caricamento di un file di script su ogni nodo ES o riabilitando lo scripting dinamico?ElasticSearch: aggregazione su _score campo w/Groovy disabilitato

mio aggregazione originale sembrava il seguente:

"aggs": { 
    "terms_agg": { 
     "terms": { 
      "field": "field1", 
      "order": {"max_score": "desc"} 
     }, 
    "aggs": { 
     "max_score": { 
      "max": {"script": "_score"} 
     }, 
     "top_terms": { 
      "top_hits": {"size": 1} 
     } 
     } 
} 

Cercando per specificare l'espressione come il Lang non sembra funzionare come ES genera un errore che indica il punteggio si può accedere solo quando viene utilizzato per ordinare. Non riesco a capire nessun altro metodo per ordinare i miei secchi per il campo del punteggio. Qualcuno ha qualche idea?

Modifica: per chiarire, la mia restrizione non è in grado di modificare il lato server. Ad esempio, non posso aggiungere o modificare nulla come parte dell'installazione o della configurazione di ES.

risposta

0

Un possibile approccio consiste nell'utilizzare le altre opzioni di script disponibili. mvel sembra non essere possibile utilizzarlo a meno che lo scripting dinamico non sia abilitato. E, a meno che a more fine-grained control of scripting enable/disable raggiunga la versione 1.6, non penso sia possibile abilitare lo scripting dinamico per e non per groovy.

Siamo lasciati con native e mustache (utilizzato per modelli) che sono abilitati per impostazione predefinita. Non penso che lo scripting personalizzato possa essere fatto con mustache, se è possibile non ho trovato un modo e siamo rimasti con lo scripting native (Java).

Ecco il mio prendere a questo:

  • creare un'implementazione di NativeScriptFactory:
package com.foo.script; 

import java.util.Map; 

import org.elasticsearch.script.ExecutableScript; 
import org.elasticsearch.script.NativeScriptFactory; 

public class MyScriptNativeScriptFactory implements NativeScriptFactory { 

    @Override 
    public ExecutableScript newScript(Map<String, Object> arg0) { 
     return new MyScript(); 
    } 

} 
  • un'implementazione di AbstractFloatSearchScript ad esempio:
package com.foo.script; 

import java.io.IOException; 

import org.elasticsearch.script.AbstractFloatSearchScript; 

public class MyScript extends AbstractFloatSearchScript { 

    @Override 
    public float runAsFloat() { 
     try { 
      return score(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return 0; 
    } 

} 
  • alternativa, costruire un semplice progetto Maven per legare tutti insieme. pom.xml:
<properties> 
    <elasticsearch.version>1.5.2</elasticsearch.version> 
    <maven.compiler.source>1.8</maven.compiler.source> 
    <maven.compiler.target>1.8</maven.compiler.target> 
</properties> 

<dependencies> 
    <dependency> 
     <groupId>org.elasticsearch</groupId> 
     <artifactId>elasticsearch</artifactId> 
     <version>${elasticsearch.version}</version> 
     <scope>compile</scope> 
    </dependency> 
</dependencies> 

<build> 
    <sourceDirectory>src</sourceDirectory> 
    <plugins> 
     <plugin> 
      <artifactId>maven-compiler-plugin</artifactId> 
      <version>3.1</version> 
      <configuration> 
       <source>1.8</source> 
       <target>1.8</target> 
      </configuration> 
     </plugin> 
    </plugins> 
</build> 
  • costruirla e ottenere il file jar risultante.
  • posto il barattolo all'interno [ES_folder]/lib
  • modificare elasticsearch.yml e aggiungere script.native.my_script.type: com.foo.script.MyScriptNativeScriptFactory

  • riavvio nodi ES.

  • usano in aggregazioni:
{ 
    "aggs": { 
    "max_score": { 
     "max": { 
     "script": "my_script", 
     "lang": "native" 
     } 
    } 
    } 
} 

mio esempio sopra riportato solo restituisce il _score come uno script, ma, naturalmente, può essere utilizzato in scenari più avanzati.

MODIFICA: se non ti è permesso toccare le istanze, allora non penso che tu abbia alcuna opzione.

+0

Sfortunatamente non è una soluzione ideale. Inoltre, sarebbe molto più semplice scrivere semplicemente uno script groovy e inserirlo in /scripts /. Per esempio, nel mio caso potrei scrivere '_score' in un file chiamato _score.groovy e inserirlo negli script/e verrebbe automaticamente raccolto da ES. Dal mio test, non avrei nemmeno dovuto cambiare il codice "{" script ":" _score "}' per usare "script_file", avrebbe funzionato. Il problema è che questa soluzione richiede l'accesso diretto per modificare i nodi, cosa che non posso garantire. – user4872035

+0

Ti ho dato un'alternativa, l'unica possibile a mio avviso, date le tue restrizioni. Hai detto che non vuoi usare Groovy (a causa della cosa dinamica di scripting) e non vuoi "caricare un file di script su ogni nodo ES o riabilitare lo scripting dinamico". Se, invece, vuoi usare i file di script, allora sì - più facile, ma hai detto che non vuoi farlo. Se mantieni le tue restrizioni iniziali, non penso ci sia altro modo che uno script 'nativo'. Saluti. –

+0

Ah, quindi suppongo che le mie restrizioni non fossero abbastanza chiare, dato che la tua alternativa cade in quel secchio (nessun gioco di parole). La mia restrizione è un cluster ES su cui non ho alcun controllo e non posso modificare la configurazione di. Modificherò il post per chiarire. Grazie! – user4872035

0

ElasticSearch almeno della versione 1.7.1 e possibilmente precedente offre anche l'uso del linguaggio di scripting di espressione di Lucene - e come Expression è sandbox per impostazione predefinita può essere utilizzato per script dinamici in linea nello stesso modo in cui è stato Groovy. Nel nostro caso, dove il nostro cluster ES di produzione è stato appena aggiornato dalla 1.4.1 alla 1.7.1, abbiamo deciso di non usare più Groovy a causa della sua natura non sandbox, anche se vogliamo davvero fare uso di script dinamici a causa di la facilità di implementazione e la flessibilità che offrono mentre continuiamo a perfezionare la nostra applicazione e il suo livello di ricerca.

Mentre scrivere uno script Java nativo come sostituto per i nostri punteggi di funzione Groovy dinamici potrebbe anche essere stata una possibilità nel nostro caso, volevamo esaminare la fattibilità dell'utilizzo di Expression per il nostro linguaggio di scripting dinamico in linea. Dopo aver letto la documentazione, ho potuto semplicemente modificare l'attributo "lang" da "groovy" a "expression" nei nostri script in linea function_score e con la proprietà script.inline: sandbox impostata nel file .../config/elasticsearch.yml: lo script di punteggio della funzione funzionava senza altre modifiche. Pertanto, ora possiamo continuare a utilizzare lo scripting dinamico in linea in ElasticSearch, e farlo con sandboxing abilitato (come Expression è sandboxed per impostazione predefinita). Ovviamente devono essere implementate anche altre misure di sicurezza come l'esecuzione del cluster ES dietro un proxy applicativo e un firewall per garantire che gli utenti esterni non abbiano accesso diretto ai nodi ES o alle API ES. Tuttavia, questo è stato un cambiamento molto semplice, che per ora ha risolto un problema con la mancanza di sandboxing di Groovy e le preoccupazioni su come abilitarlo a funzionare senza sandboxing.

Mentre passare gli script dinamici a Expression può solo funzionare o essere applicabile in alcuni casi (a seconda della complessità degli script dinamici in linea), è sembrato che valesse la pena condividere queste informazioni nella speranza che potesse aiutare altri sviluppatori.

Come nota, uno degli altri linguaggi di scripting ES supportati, Moustache sembra essere utilizzabile solo per la creazione di modelli all'interno delle query di ricerca. Non sembra essere utilizzabile per nessuno dei più complessi bisogni di scripting come function_score, ecc., Anche se non sono sicuro che ciò fosse del tutto evidente durante la prima lettura della documentazione ES aggiornata.

Infine, un ulteriore problema di essere consapevoli è che l'utilizzo di script Espressione Lucene sono contrassegnati come una funzione sperimentale nell'ultima versione ES e la documentazione osserva che come tale estensione di script è in fase di significativo lavoro di sviluppo in questo tempo, il suo utilizzo o funzionalità potrebbero cambiare nelle versioni successive di ES. Pertanto, se si passa a utilizzare Expression per uno qualsiasi degli script (dinamici o di altro tipo), è necessario notare nelle note della documentazione/sviluppatore di rivedere tali modifiche prima di aggiornare l'installazione ES la volta successiva per garantire che gli script rimangano compatibili e funzionino come previsto.

Almeno per la nostra situazione, a meno che non fossimo disposti a consentire l'attivazione di script dinamici non sandboxed nell'ultima versione di ES (tramite l'opzione script.inline: on) in modo che gli script Groovy inline possano continuare a essere eseguiti, passando a Gli script di Lucene Expression sembravano l'opzione migliore per ora.

Sarà interessante vedere quali cambiamenti si verificano nelle scelte di scripting per ES nelle versioni future, soprattutto considerando che l'opzione (apparentemente inefficace) di sandboxing per Groovy verrà completamente rimossa dalla versione 2.0. Speriamo che altre protezioni possano essere messe in atto per abilitare l'uso dinamico di Groovy, o forse lo script di Lucene Expression prenderà il posto di Groovy e abiliterà tutti i tipi di script dinamici che gli sviluppatori stanno già facendo uso di.

Per ulteriori note su Lucene Expression consultare la documentazione ES qui: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html#_lucene_expressions_scripts - questa pagina è anche la fonte della nota riguardante la rimozione pianificata dell'opzione di sandboxing di Groovy da ES v2.0 +. Ulteriori documentazione di Lucene Expression possono essere trovate qui: http://lucene.apache.org/core/4_9_0/expressions/index.html?org/apache/lucene/expressions/js/package-summary.html

Problemi correlati