2016-02-11 22 views
6

Non riesco proprio a ottenere la sintassi corretta per la mappatura multi campo in NEST 2.0, se questa è la terminologia corretta. Ogni esempio che ho trovato per la mappatura sembra essere < = la versione 1.x di NEST. Sono nuovo di Elasticsearch e NEST e ho letto la loro documentazione, ma la documentazione di NEST non è stata completamente aggiornata per 2.x.Creare indice con sintassi di mappatura multi campo con NEST 2.x

Fondamentalmente, non è necessario indicizzare o memorizzare l'intero tipo. Alcuni campi di cui ho bisogno solo per l'indicizzazione, alcuni campi che ho bisogno di indicizzare e recuperare, e alcuni non ho bisogno di indicizzazione, solo per il recupero.

MyType 
{ 
    // Index this & allow for retrieval. 
    int Id { get; set; } 

    // Index this & allow for retrieval. 
    // **Also**, in my searching & sorting, I need to sort on this **entire** field, not just individual tokens. 
    string CompanyName { get; set; } 

    // Don't index this for searching, but do store for display. 
    DateTime CreatedDate { get; set; } 

    // Index this for searching BUT NOT for retrieval/displaying. 
    string CompanyDescription { get; set; } 

    // Nest this. 
    List<MyChildType> Locations { get; set; } 
} 

MyChildType 
{ 
    // Index this & allow for retrieval. 
    string LocationName { get; set; } 

    // etc. other properties. 
} 

Sono hanno stato in grado di indicizzare l'intero oggetto e il bambino così come sono utilizzando il seguente come esempio:

client.Index(item, i => i.Index(indexName)); 

Tuttavia, l'oggetto reale è molto più grande di questo e davvero non ne ho più bisogno. Ho trovato questo, che sembra quello che penso di voler fare, ma in una versione precedente: multi field mapping elasticsearch

Penso che "mappatura" è quello che sto andando, ma come ho detto, sono nuovo a Elasticsearch e NEST e sto cercando di imparare la terminologia.

Sii gentile! :) È la prima volta che faccio una domanda su SO. Grazie!

risposta

0

Penso che tu abbia almeno 2 possibilità per risolvere il problema:

  1. Su indicizzazione: creare qualcosa come un modello di metadati, che è memorizzato solo per il recupero. Vedere lo _source field per limitare il ritorno a questo campo.
  2. Durante la ricerca: specificare i campi che si desidera interrogare: se non si desidera eseguire una query su CreatedDate, non includerlo nella ricerca.

Nel mio caso sto usando entrambi questi approcci per ottenere risultati molto veloce :-)

6

Per quanto posso vedere, non si dispone di tutti i tipi complessi che si sta tentando mappa. Quindi puoi facilmente utilizzare gli attributi NEST per mappare i tuoi oggetti.

Check this out:

[Nest.ElasticsearchType] 
public class MyType 
{ 
    // Index this & allow for retrieval. 
    [Nest.Number(Store=true)] 
    int Id { get; set; } 

    // Index this & allow for retrieval. 
    // **Also**, in my searching & sorting, I need to sort on this **entire** field, not just individual tokens. 
    [Nest.String(Store = true, Index=Nest.FieldIndexOption.Analyzed, TermVector=Nest.TermVectorOption.WithPositionsOffsets)] 
    string CompanyName { get; set; } 

    // Don't index this for searching, but do store for display. 
    [Nest.Date(Store=true, Index=Nest.NonStringIndexOption.No)] 
    DateTime CreatedDate { get; set; } 

    // Index this for searching BUT NOT for retrieval/displaying. 
    [Nest.String(Store=false, Index=Nest.FieldIndexOption.Analyzed)] 
    string CompanyDescription { get; set; } 

    [Nest.Nested(Store=true, IncludeInAll=true)] 
    // Nest this. 
    List<MyChildType> Locations { get; set; } 
} 

[Nest.ElasticsearchType] 
public class MyChildType 
{ 
    // Index this & allow for retrieval. 
    [Nest.String(Store=true, Index = Nest.FieldIndexOption.Analyzed)] 
    string LocationName { get; set; } 

    // etc. other properties. 
} 

Dopo questa dichiarazione, per creare questa mappatura elasticsearch è necessario effettuare una chiamata simile a:

var mappingResponse = elasticClient.Map<MyType>(m => m.AutoMap()); 

Con AutoMap() chiamano NEST leggerà la tua attributi dal tuo POCO e creare una richiesta di mappatura di conseguenza.

Vedere anche la sezione "Mappatura basata sugli attributi" da here.

Cheers!

3

Al momento della scrittura, Nest non offre un modo per mappare una proprietà della classe a più campi nel mapping del documento utilizzando gli attributi incorporati. Tuttavia, fornisce le strutture necessarie per fare qualsiasi cosa con le tue mappature che potresti fare se hai scritto tu stesso il JSON.

Ecco una soluzione che ho messo insieme per le mie esigenze. Non dovrebbe essere difficile usarlo come punto di partenza per qualsiasi cosa tu debba fare.

In primo luogo, ecco un esempio della mappatura voglio generare

{ 
    "product":{ 
     "properties":{ 
     "name":{ 
      "type":"string", 
      "index":"not_analyzed", 
      "fields":{ 
       "standard":{ 
        "type":"string", 
        "analyzer":"standard" 
       } 
      } 
     } 
     } 
    } 
} 

Il documento product avrebbe allora il campo name, che è indicizzato, ma non analizzato, e il campo name.standard, che utilizza l'analizzatore di serie .

Il # di classe C che ho generato la mappatura da sguardi come questo

[ElasticsearchType] 
public class Product 
{ 
    [WantsStandardAnalysisField] 
    public string Name { get; set; } 
} 

Nota l'attributo WantsStandardAnalysisField. Questo è un attributo personalizzato senza aggiunte speciali. Letteralmente solo:

public class WantsStandardAnalysisField : Attribute {} 

Se dovessi usare AutoMap come-si, il mio attributo personalizzato sarebbe stato ignorato e vorrei avere una mappatura che ha il campo name, ma non name.standard. Fortunatamente, AutoMap accetta un'istanza di IPropertyVisitor. Una classe base chiamata NoopPropertyVisitor implementa l'interfaccia e non fa nulla, in modo da poter creare una sottoclasse e sovrascrivere solo i metodi che ti interessano. Quando utilizzi un visitatore di proprietà con AutoMap, genererà per te una mappatura del documento ma ti darà la possibilità di modificarlo prima di essere inviato a Elastic Search. Tutto quello che dobbiamo fare è cercare le proprietà contrassegnate con il nostro attributo personalizzato e aggiungere un campo a loro.

Ecco un esempio che fa questo:

public class ProductPropertyVisitor : NoopPropertyVisitor 
{ 
    public override void Visit(IStringProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) 
    { 
     base.Visit(type, propertyInfo, attribute); 

     var wsaf = propertyInfo.GetCustomAttribute<WantsStandardAnalysisField>(); 
     if (wsaf != null) 
     { 
      type.Index = FieldIndexOption.NotAnalyzed; 
      type.Fields = new Properties 
      { 
       { 
        "standard", 
        new StringProperty 
        { 
         Index = FieldIndexOption.Analyzed, 
         Analyzer = "standard" 
        } 
       } 
      }; 
     } 
    } 
} 

Come potete vedere, siamo in grado di fare praticamente tutto quello che vogliamo con la proprietà generato, tra cui lo spegnimento di analisi per la proprietà principale e l'aggiunta di un nuovo campo con le sue impostazioni. Per divertimento, è possibile aggiungere un paio di proprietà all'attributo personalizzato che consente di specificare il nome del campo che si desidera e l'analizzatore da utilizzare. Potresti anche modificare il codice per vedere se l'attributo è stato aggiunto più volte, permettendoti di aggiungere tutti i campi che desideri.

Se si dovesse eseguire questo attraverso qualsiasi metodo che genera una mappatura utilizzando AutoMap, come ad esempio:

new TypeMappingDescriptor<Product>().AutoMap(new ProductPropertyVisitor()) 

Si otterrà la mappatura multi-campo desiderato. Ora puoi personalizzare i mapping sul contenuto del tuo cuore. Godere!

5

Oltre alle risposte Colin's e Selçuk's, è inoltre possibile controllare completamente la mappatura tramite l'API di mappatura fluente (e di inizializzazione dell'oggetto). Ecco un esempio in base alle vostre esigenze

void Main() 
{ 
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); 
    var connectionSettings = new ConnectionSettings(pool); 

    var client = new ElasticClient(connectionSettings); 

    client.Map<MyType>(m => m 
     .Index("index-name") 
     .AutoMap() 
     .Properties(p => p 
      .String(s => s 
       .Name(n => n.CompanyName) 
       .Fields(f => f 
        .String(ss => ss 
         .Name("raw") 
         .NotAnalyzed() 
        ) 
       ) 
      ) 
      .Date(d => d 
       .Name(n => n.CreatedDate) 
       .Index(NonStringIndexOption.No)   
      ) 
      .String(s => s 
       .Name(n => n.CompanyDescription) 
       .Store(false) 
      ) 
      .Nested<MyChildType>(n => n 
       .Name(nn => nn.Locations.First()) 
       .AutoMap() 
       .Properties(pp => pp 
        /* properties of MyChildType */ 
       ) 
      ) 
     ) 
    ); 
} 

public class MyType 
{ 
    // Index this & allow for retrieval. 
    public int Id { get; set; } 

    // Index this & allow for retrieval. 
    // **Also**, in my searching & sorting, I need to sort on this **entire** field, not just individual tokens. 
    public string CompanyName { get; set; } 

    // Don't index this for searching, but do store for display. 
    public DateTime CreatedDate { get; set; } 

    // Index this for searching BUT NOT for retrieval/displaying. 
    public string CompanyDescription { get; set; } 

    // Nest this. 
    public List<MyChildType> Locations { get; set; } 
} 

public class MyChildType 
{ 
    // Index this & allow for retrieval. 
    public string LocationName { get; set; } 

    // etc. other properties. 
} 

Questo produce la mappatura

{ 
    "properties": { 
    "id": { 
     "type": "integer" 
    }, 
    "companyName": { 
     "type": "string", 
     "fields": { 
     "raw": { 
      "type": "string", 
      "index": "not_analyzed" 
     } 
     } 
    }, 
    "createdDate": { 
     "type": "date", 
     "index": "no" 
    }, 
    "companyDescription": { 
     "type": "string", 
     "store": false 
    }, 
    "locations": { 
     "type": "nested", 
     "properties": { 
     "locationName": { 
      "type": "string" 
     } 
     } 
    } 
    } 
} 

Calling .AutoMap() cause NEST per dedurre la mappatura in base ai tipi di proprietà ed eventuali attributi applicati a loro. Quindi .Properties() esegue l'override di tutti i mapping dedotti.Ad esempio

  • CompanyName viene mappato come multi_field con il campo companyName analizzato usando l'analizzatore standard companyName.raw non analizzato. È possibile fare riferimento a quest'ultimo nelle query utilizzando .Field(f => f.CompanyName.Suffix("raw"))
  • Locations è mappato come un tipo nested (la mappatura automatica per impostazione predefinita lo deduce come un tipo di mappatura object). È quindi possibile definire qualsiasi mapping specifico per MyChildType utilizzando .Properties() all'interno della chiamata Nested<MyChildType>().
+0

Davvero una bella risposta. Sembra funzionare principalmente per me, tuttavia, ho avuto un problema con l'uso di '.Suffix (" raw ")' in Nest 2.4.2 (semplicemente non funzionava). Ho appena usato '+" .raw "' alla fine. – Harvey

Problemi correlati