2013-01-14 11 views
5

Sto lavorando con un'applicazione Rails 3 per consentire alle persone di richiedere sovvenzioni e simili. Stiamo usando Elasticsearch/Tire come motore di ricerca.Appiattimento di una relazione AR polimorfa con Elasticsearch/Tyre

I documenti, ad esempio le proposte di sussidio, sono composti da molte risposte di tipi diversi, ad esempio informazioni di contatto o saggi. In AR, (DBS relazionali in generale) non è possibile specificare un polimorfica relazione "has_many" direttamente, così invece:

class Document < ActiveRecord::Base 
    has_many :answerings 
end 

class Answering < ActiveRecord::Base 
    belongs_to :document 
    belongs_to :question 
    belongs_to :payload, :polymorphic => true 
end 

"payload" sono modelli per i singoli tipi di risposta: Contatti, narrazioni, a scelta multipla, e presto. (Questi modelli sono namespace sotto "risponde.")

class Answerable::Narrative < ActiveRecord::Base 
    has_one :answering, :as => :payload 
    validates_presence_of :narrative_content 
end 

class Answerable::Contact < ActiveRecord::Base 
    has_one :answering, :as => :payload 
    validates_presence_of :fname, :lname, :city, :state, :zip... 
end 

Concettualmente, l'idea è una risposta è composto da una segreteria (funzioni come un tavolo da unire, negozi di metadati comune a tutte le risposte) e un responsabile (che memorizza il contenuto effettivo della risposta). Funziona perfettamente per la scrittura di dati. Cerca e recupera, non tanto.

Voglio utilizzare Tyre/ES per esporre una rappresentazione più sana dei miei dati per la ricerca e la lettura. In una normale configurazione di Tyre, finirei con (a) un indice per le risposte e (b) indici separati per narrativa, contatti, scelte multiple e così via. Invece, mi piacerebbe solo archiviare documenti e risposte, possibilmente come genitore/figlio. L'indice Answers unirebbe i dati delle risposte (id, question_id, updated_at ...) e Answerables (fname, lname, email ...). In questo modo, posso cercare le risposte da un singolo indice, filtrare per tipo, question_id, id_documento, ecc. Gli aggiornamenti verranno attivati ​​dalla risposta, ma ciascuna risposta inserirà quindi le informazioni dal suo answerable. Sto usando RABL per modellare gli input dei miei motori di ricerca, quindi è abbastanza facile.

Answering.find(123).to_indexed_json # let's say it's a narrative 
=> { id: 123, question_id: 10, :document_id: 24, updated_at: ..., updated_by: [email protected], narrative_content: "Back in the day, when I was a teenager, before I had...", answerable_type: "narrative" } 

Quindi, ho un paio di domande.

  1. L'obiettivo è fornire una soluzione a query singola per tutte le risposte, indipendentemente dal tipo (rispondente) sottostante. Non ho mai impostato qualcosa di simile prima. Questo sembra un approccio sano al problema? Puoi prevedere le rughe che non posso? Alternative/suggerimenti/etc. prego.
  2. La parte difficile, come la vedo io, è la mappatura. Il mio piano è quello di mettere mapping espliciti nel modello di risposta per i campi che hanno bisogno di opzioni di indicizzazione, e lasciare che i mapping predefiniti prendersi cura di tutto il resto:

    mapping do 
        indexes :question_id, :index => :not_analyzed 
        indexes :document_id, :index => :not_analyzed 
        indexes :narrative_content, :analyzer => :snowball 
        indexes :junk_collection_total, :index => :not_analyzed 
        indexes :some_other_crazy_field, :index 
        [...] 
    

    Se non si specifica una mappatura per qualche campo, (per esempio, "fname") Tire/ES riporterà la mappatura dinamica? (Dovrei mappare esplicitamente ogni campo che verrà utilizzato?)

Grazie in anticipo. Per favore fatemi sapere se posso essere più specifico.

risposta

0

L'indicizzazione è la giusta soluzione. Insieme ai nomi dei campi di indicizzazione, puoi indicizzare i risultati dei metodi.

mapping do 
    indexes :payload_details, :as => 'payload_details', :analyzer => 'snowball',:boost => 0 
end 

def payload_details 
    "#{payload.fname} #{payload.lname}" #etc. 
end 

Il valore indicizzato diventa un tipo di anatra, quindi se indice di tutti i valori che si fa riferimento a suo parere, i dati saranno disponibili. Se si accede ad un attributo che non è indicizzato sul modello dell'elemento indicizzato, verrà catturata l'istanza da ActiveRecord, se si accede a un attributo di un modello correlato, sono quasi certo che si ottiene un errore di riferimento, ma il finder dinamico potrebbe rilevare.

Problemi correlati