使用 Elasticsearch [Ruby、ActiveRecord、elasticsearch-model 进行关联模型搜索的方法

Approach for associated model searching with Elasticsearch [Ruby, ActiveRecord, elasticsearch-model]

我有一个关于在 Elasticsearch 中搜索时选择最佳方法的问题。

我有Ruby关RailsAPI,有ActiveRecord,还有Elasticsearch(elasticsearch-modelgem) .

这是一个简单的 API,其中 returns projects(项目 AR 模型),我在其中设置索引:

mapping dynamic: false do
indexes :created_at, type: 'date'
end

然后我直接从控制器搜索 Elasticsearch 和 return AR 关系。它运行良好。

现在我正在尝试将 categories 添加到 projects,如 categories has_many projectsprojects belongs_to categories。我想知道两件事:

我现在应该如何查询以获取特定类别的项目,我应该将其重新实现为 return result = Category.search(...) 和 return result.jobs,还是仍然通过以下方式寻求projects,但按 category_id?

搜索

如何在 Elasticsearch 中结合 CategoryProject 以实现从特定类别和多个类别中搜索项目?合并映射?

提前致谢!

我的第一个想法是您的用例非常简单。您根本不需要 Elasticsearch。您可以简化并仅使用 ActiveRecord,select by SQL 和 return 记录。您不需要 Elasticsearch 为您的用例提供的任何功能,这样做只是为您自己创造更多的工作。

但是,我假设您进行迭代开发并且您的使用会变得更加复杂。证明使用 Elasticsearch 的合理性。

关系和非关系数据

ActiveRecord 是一个 ORM for relational data. Typicalhttps://www.elastic.co/guide/en/elasticsearch/reference/current/documents-indices.htmlly it sits on top of a Structured Query Language 强大的关系数据库。它非常好地支持关系(Rails 说法中的关联)。

Elasticsearch 是 non relational document store,在倒排索引中将信息存储为 JSON。这允许非常快速的全文搜索(以及其他用途)。它不能很好地支持文档之间的关系。它旨在不关联数据!它希望您不存储关系,而是不断重复数据,这与 SQL 方法相反。这称为非规范化,更多内容见下文。

这些是关于数据存储的非常不同的思考方式!这并不意味着他们在一起玩得不好。如果使用得当,它们可以很好地协同工作。然而,他们采取不同的思维方式。在我看来,重要的是要很好地掌握每个背后的基础知识,以便对如何使用它们做出合理的判断。

Elasticsearch 很棒 documentation。我建议您花几个小时阅读它。

Elasticsearch 是如何做关联的?

您关心问题中的基本 has-many 关联,那么 Elastic 如何处理这些关联?有哪些选择?

There are 4 major options. I think you should denormalize 您的数据在这里。

我想你想 return 某些类别的所有项目。因此,您应该创建一个索引,其中包含每个类别的文档。每个类别都应包含其项目的完整列表。然后,您可以查询类别和 return 所有项目。

这是一种方法。您的用例非常简单,对我来说感觉有点矫枉过正,您可以使用上面链接的 Elasticsearch 的 4 个主要选项中的任何一个来解决这个问题。或者理想情况下根本不使用 Elasticsearch。

如果您提供有关用例的更多详细信息,我将能够更多地讨论您可以使用的方法。

// 映射(嵌套类别)

 mapping dynamic: false do
  indexes :created_at, type: 'date'
  indexes :categories, type: 'nested' do
    indexes :name, type: :text, analyzer: :english
  end 
 end

// json

  def as_indexed_json(_options = nil)
  { 
   created_at: created_at,
   # in case project belong_to category  
   # categories: [category.name, Category::DEFAULT].map do ... 
   categories: categories.map do |category|
     {
       name: category.name
     }
   end
  } 
 end

// 搜索功能(elasticsearch DSL) 因为你想按类别搜索项目

def by_categories(categories)
  filters = []
  categories.each { |category|
    filters.push term: {"categories.name":category.name}
  }
  Project.__elasticsearch__.search(
     query: {            
        nested: {
           path: "categories",
           query: {
              bool: {
                 filter:{
                    bool:{
                        should:filters                                       
                    }
                  }
               }
            }
        }    
     }
  )
end