Выравнивание полиморфного отношения AR с помощью Elasticsearch/Tire

Я работаю с приложением Rails 3, чтобы люди могли подавать заявки на гранты и тому подобное. Мы используем Elasticsearch/Tire в качестве поисковой системы.

Документы, например заявки на гранты, состоят из множества ответов разных типов, таких как контактная информация или эссе. В AR (реляционные базы данных в целом) вы не можете напрямую указать полиморфное отношение has_many, поэтому вместо этого:

class Document < ActiveRecord::Base
  has_many :answerings
end

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

«Полезная нагрузка» — это модели для отдельных типов ответов: контакты, повествования, множественный выбор и так далее. (Эти модели находятся в пространстве имен в разделе «Отвечает».)

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

Концептуально идея заключается в том, что ответ состоит из ответа (функционирует как сводная таблица, хранит метаданные, общие для всех ответов) и ответа (в котором хранится фактическое содержание ответа). Это прекрасно работает. для записи данных. Поиск и поиск, не так уж и много.

Я хочу использовать Tire/ES, чтобы предоставить более разумное представление моих данных для поиска и чтения. В обычной настройке Tire я бы получил (а) индекс для ответов и (б) отдельные индексы для повествований, контактов, множественного выбора и так далее. Вместо этого я хотел бы просто хранить документы и ответы, возможно, как родитель/дочерний элемент. Индекс ответов будет объединять данные из ответов (id, question_id, updated_at...) и ответов (fname, lname, email...). Таким образом, я могу искать ответы в одном индексе, фильтровать по типу, question_id, document_id и т. д. Обновления будут запускаться из ответа, но каждый ответ затем будет извлекать информацию из своего ответа. Я использую RABL для шаблонизации входных данных поисковой системы, так что это достаточно просто.

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" }

Итак, у меня есть пара вопросов.

  1. Цель состоит в том, чтобы предоставить решение с одним запросом для всех ответов, независимо от базового (отвечающего) типа. Я никогда раньше не устанавливал ничего подобного. Кажется ли это разумным подходом к проблеме? Ты можешь предвидеть морщины, которых я не могу? Альтернативы/предложения/и т.д. приветствуются.
  2. Самая сложная часть, на мой взгляд, это картографирование. Мой план состоит в том, чтобы поместить явные сопоставления в модель ответа для полей, которым нужны параметры индексации, и просто позволить сопоставлениям по умолчанию позаботиться обо всем остальном:

    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
      [...]
    

    Если я не укажу сопоставление для некоторого поля (скажем, «fname»), вернется ли Tire/ES к динамическому сопоставлению? (Должен ли я явно отображать каждое поле, которое будет использоваться?)

Заранее спасибо. Пожалуйста, дайте мне знать, если я могу быть более конкретным.


person Erik    schedule 14.01.2013    source источник


Ответы (1)


Индексация - правильный способ сделать это. Наряду с именами полей индексации вы можете индексировать результаты методов.

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

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

Индексированное значение становится утиным, поэтому, если вы проиндексируете все значения, на которые вы ссылаетесь в своем представлении, данные будут доступны. Если вы получите доступ к атрибуту, который не проиндексирован в модели индексированного элемента, он захватит экземпляр из ActiveRecord, если вы получите доступ к атрибуту связанной модели, я почти уверен, что вы получите ошибку ссылки, но динамический поиск может перенимать.

person t_itchy    schedule 02.07.2013