2015-07-01 11 views
6

La nostra API REST consente agli utenti di aggiungere JSON di schemi personalizzati ad alcune delle nostre risorse REST e abbiamo bisogno che siano ricercabili in Elasticsearch. Questi dati personalizzati e la sua struttura possono essere completamente diversi tra le risorse dello stesso tipo.Supporto Schemaless per query di ricerca elastica

considerare questo documento di esempio:

{ 
    "givenName": "Joe", 
    "username": "joe", 
    "email": "[email protected]", 
    "customData": { 
    "favoriteColor": "red", 
    "someObject": { 
     "someKey": "someValue" 
    } 
    } 
} 

Tutti i campi ad eccezione customData aderire a uno schema. customData è sempre un oggetto JSON, ma tutti i campi e i valori all'interno di tale oggetto possono variare notevolmente da una risorsa all'altra. Non vi è alcuna garanzia che qualsiasi nome o valore di campo specificato (o anche il tipo di valore) all'interno di customData sia uguale tra le due risorse in quanto gli utenti possono modificare questi campi come desiderano.

Qual è il modo migliore per supportare la ricerca di questo?

Abbiamo pensato che una soluzione sarebbe semplicemente non creare alcuna mappatura per customData quando l'indice è stato creato, ma poi diventa inaccessibile (che è contraria a ciò che è ES docs say). Questa sarebbe la soluzione ideale se le query su proprietà non mappate funzionassero e non ci fossero problemi di prestazioni con questo approccio. Tuttavia, dopo aver eseguito più test, non siamo riusciti a farlo funzionare.

È qualcosa che richiede una configurazione speciale? O i documenti sono errati? Sarebbe molto apprezzato qualche chiarimento sul motivo per cui non funziona.

Dal momento che questo non è attualmente lavorando per noi, abbiamo pensato a un paio di soluzioni alternative:

  1. Reindicizzazione: questo sarebbe costoso come avremmo bisogno di reindicizzare ogni indice che contiene il documento e fare così ogni volta che un utente aggiorna una proprietà con un diverso tipo di valore. Davvero pessimo per le prestazioni, quindi probabilmente non è un'opzione reale.

  2. Utilizzare multi-match query: faremolo aggiungendo una stringa casuale al nome del campo customData ogni volta che si modifica l'oggetto customData. Ad esempio, questo è ciò che il documento viene indicizzato sarebbe simile:

    { 
        "givenName": "Joe", 
        "username": "joe", 
        "email": "[email protected]", 
        "customData_03ae8b95-2496-4c8d-9330-6d2058b1bbb9": { 
        "favoriteColor": "red", 
        "someObject": { 
         "someKey": "someValue" 
        } 
        } 
    } 
    

    Ciò significa ES creerebbe una nuova mappatura per ogni campo 'random', e vorremmo usare l'espressione di query multi-partita con un "inizia con "jolly per i nomi dei campi durante l'esecuzione delle query. Per esempio:

    curl -XPOST 'eshost:9200/test/_search?pretty' -d ' 
    { 
        "query": { 
        "multi_match": { 
         "query" : "red", 
         "type" : "phrase", 
         "fields" : ["customData_*.favoriteColor"] 
        } 
        } 
    }' 
    

    questa potrebbe essere una soluzione praticabile, ma siamo preoccupati che avere troppi mappature come questo potrebbe influire sulle prestazioni. Ci sono ripercussioni sulla performance per avere troppe mappature su un indice? Forse la reindicizzazione periodica potrebbe alleviare troppe mappature?

    Anche questo si sente come un hack e qualcosa che dovrebbe essere gestito da ES in modo nativo. Mi sto perdendo qualcosa?

Qualsiasi suggerimento su tutto ciò sarebbe molto apprezzato.

Grazie!

risposta

0

I campi con la stessa mappatura verranno memorizzati come lo stesso campo di lucene nell'indice di lucene (frammento Elasticsearch).Diversi campi lucene avranno un indice invertito separato (termine dict e voce indice) e valori doc separati. Lucene è altamente ottimizzato per archiviare documenti dello stesso campo in modo compresso. L'utilizzo di una mappatura con campi diversi per documenti diversi impedisce a Lucene di fare la sua ottimizzazione.

È consigliabile utilizzare il documento annidato Elasticsearch per eseguire ricerche in modo efficiente. La tecnologia di base è Lucene BlockJoin, che indicizza i documenti padre/figlio come un blocco di documenti.

+0

stai dicendo che il documento annidato può gestire la natura non deterministica descritta dell'oggetto 'customData'? –

2

Hai ragione che Elasticsearch non è veramente schematico. Se non viene specificata alcuna mappatura, Elasticsearch deduce i primitivi del tipo di campo in base al primo valore che vede per quel campo. Pertanto il tuo oggetto customData non deterministico può metterti nei guai se per la prima volta vedi "favoriteColor": 10 seguito da "favoriteColor": "red".

Per le vostre esigenze, si dovrebbe dare un'occhiata a SIREn Solutions elasticsearch plugin che fornisce una soluzione schemaless accoppiato con un linguaggio di interrogazione avanzata (utilizzando Twig) e un formato personalizzato indice di Lucene per velocizzare le operazioni di indicizzazione e di ricerca per i dati non deterministico .

+0

Grazie per il commento Peter - lo proveremo e assegneremo la risposta se funziona come previsto. –