0

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

我有 Ruby off Rails API,ActiveRecord以及Elasticsearchelasticsearch-modelgem)。

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

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

然后我简单地在 Elasticsearch 上进行搜索并直接从控制器返回 AR 关系。它运行良好。

现在我正在尝试添加categoriesprojects、 ascategories has_many projectsprojects belongs_to categories. 我想知道两件事:

现在我应该如何查询以获取特定类别的项目,我应该重新实现它以返回result = Category.search(...)和返回result.jobs,还是仍然搜索projects,但搜索category_id

如何在 Elasticsearch 中结合CategoryProject以使从特定类别和多个类别中搜索项目成为可能?合并映射?

提前致谢!

4

2 回答 2

1

我的第一个问题是你的用例非常简单。你根本不需要 Elasticsearch。您可以简化并仅使用 ActiveRecord,通过 SQL 选择并返回记录。您不需要 Elasticsearch 为您的用例提供的任何功能,您只是在为自己创建更多工作。

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

关系和非关系数据

ActiveRecord 是关系数据的ORM。典型的 https://www.elastic.co/guide/en/elasticsearch/reference/current/documents-indices.htmlly 它位于结构化查询语言驱动的关系数据库之上。它非常好地支持关系(Rails 用语中的关联)。

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

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

Elasticsearch 有很好的 文档。我建议你花几个小时阅读它。

Elasticsearch 如何进行关联?

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

有 4 个主要选项。我认为你应该在这里非规范化你的数据。

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

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

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

于 2020-02-19T11:30:56.943 回答
1

// 映射(嵌套类别)

 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
于 2020-02-19T12:23:58.097 回答