2014-11-04 8 views
7

Sto costruendo un'applicazione API che consente essenzialmente a un utente di creare un documento, che può essere strutturato come preferisce, che verrà archiviato in Elasticsearch. In sostanza, sto fornendo un'interfaccia semplice per gli utenti per accedere alla nostra istanza Elasticsearch. Sto cercando di mantenere l'implementazione il più semplice possibile. Ecco cosa ho a che fare finora. Indicizzare un oggetto dinamico utilizzando NEST

L'oggetto per il corpo atteso:

public class DocumentModel 
{ 
    public string Index { get; set; } 
    public string Type { get; set; } 
    public string Id { get; set; } 
    [ElasticProperty(Type = FieldType.Nested)] 
    public dynamic Document { get; set; } 
} 

semplice implementazione:

[HttpPost] 
[Route("")] 
public IHttpActionResult Post(DocumentModel document) 
{ 
    Uri nodeLocation = new Uri("http://localhost:9200"); 
    IConnectionPool connectionPool = new SniffingConnectionPool(new List<Uri> { nodeLocation }); 
    ConnectionSettings settings = new ConnectionSettings(connectionPool); 
    ElasticClient esClient = new ElasticClient(settings); 

    IIndexResponse result = esClient.Index(document, i => i 
     .Index(document.Index) 
     .Type(document.Type) 
     .Id(document.Id)); 

    return Ok(result.IsValid); 
} 

Questo funziona bene, ma include l'Indice, tipo, e Id nella fonte. Quello che mi piacerebbe davvero fare è semplicemente fornire queste tre informazioni durante l'indicizzazione, ma in realtà basta indicizzare document.Document, che è di tipo dinamico. Ma, che sembra essere d'accordo con Nest, in quanto genera un errore nella IDE e al momento della compilazione:

"Un gruppo di funzione o un metodo anonimo non può essere utilizzato come un valore costitutivo di un'operazione legata in modo dinamico"

"Impossibile utilizzare un'espressione lambda come argomento per un'operazione inviata dinamicamente senza prima convertirla in un tipo di albero delegato o di espressione".

Come posso indicizzare solo document.Document? C'è un modo migliore per gestire un documento JSON in arrivo di struttura sconosciuta rispetto all'utilizzo di un tipo dinamico?

risposta

15

Ci sono un paio di modi per farlo.

Cercando di indicizzare il documento come tipo dinamico non funzionerà, ma è possibile indicizzarlo come oggetto tramite l'oggetto IndexRequest.

dynamic dynamicDoc = new { /*fill in document format here*/ }; 
ElasticClient esClient = new ElasticClient(esSettings); 

IndexRequest<object> request = new IndexRequest<object>(dynamicDoc) 
{ 
    Index = "someindex", 
    Type = "SomeType", 
    Id = "someid" 
}; 

esClient.Index<object>(request); 

Oppure, se si tratta di documenti in massa

List<dynamic> Documents = new List<dynamic>(); 
//Populate Documents 

BulkDescriptor descriptor = new BulkDescriptor(); 
foreach(var doc in Documents) 
{ 
    descriptor.Index<object>(i => i 
     .Index("someindex") 
     .Type("SomeType") 
     .Id("someid") 
     .Document(doc)); 
} 

esClient.Bulk(descriptor); 

NEST (o, più precisamente, Elasticsearch.Net) ha anche una variante metodo .raw attaccato alla classe ElasticClient, che può indice grezzo JSON . Utilizzando Raw.Index() Andiamo a fare cose come questa:

string documentJson = JsonConvert.SerializeObject(document.Document); 

ElasticsearchResponse<string> result = esClient.Raw.Index(document.Index, document.Type, document.Id, documentJson); 

Il descrittore di tipo per la risposta è il tipo si aspetta la risposta di essere in (stringa significa che avrete una risposta JSON serializzato che puoi deserializzare e fare qualcosa con). Questo ci consente di evitare l'intero problema del tipo di oggetto e NEST indicizza il documento in Elasticsearch esattamente come previsto.

+0

Vorrei che Raw.Index mantenesse le relazioni genitore-figlio dal vecchio indice nel nuovo indice – Adrian

+0

In alternativa a 'dynamic' ho usato' Dictionary 'o ereditato dalla classe. Attenzione: se si eredita da 'Dictionary' NEST non si automatizzeranno automaticamente le altre proprietà sul documento (inserirle invece nel dizionario). Ciò ha funzionato bene anche per gli attributi delle variabili: gli attributi comuni sono andati nelle proprietà POCO, gli attributi delle variabili sono andati in una proprietà 'Data' (con tipo' Dictionary '). Questo metodo di massa è facile da usare. Non dimenticare di ottenere il risultato della chiamata a 'Bulk' per cercare' .Errors', ecc! – nothingisnecessary