【问题标题】:Approach for associated model searching with Elasticsearch [Ruby, ActiveRecord, elasticsearch-model]使用 Elasticsearch 进行关联模型搜索的方法 [Ruby, ActiveRecord, elasticsearch-model]
【发布时间】:2020-06-03 09:31:20
【问题描述】:

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

我有 Ruby off Rails API、ActiveRecordElasticsearch (elasticsearch-model gem)。

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

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

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

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

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

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

提前致谢!

【问题讨论】:

    标签: ruby-on-rails ruby elasticsearch activerecord elasticsearch-model


    【解决方案1】:

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

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

    关系和非关系数据

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

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

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

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

    Elasticsearch 如何进行关联?

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

    There are 4 major options. 我认为你应该在这里denormalize 你的数据。

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

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

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

    【讨论】:

    • 使用 Elasticsearch 的原因,只是在团队内部第一次尝试。然而,这不是我的决定。其中一个要求是全文搜索,但从我的角度来看,它可以通过使用 Postgres 和简单的 ActiveRecord 来实现,但团队决定始终使用 MySQL 并尝试使用 Elasticsearch。明天我会试试你的建议。来自我的网站的许多赞赏。我完全同意 ES 的方法比 AR 更难。
    【解决方案2】:

    // 映射(嵌套类别)

     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
    

    【讨论】:

    • 在我的例子中,项目属于_to类别,所以模型只有一个category_id属性。所以我只能像project.category那样做,而不是所有类别。在项目 has_many 类别的情况下它可以工作,但如何以相反的方式处理它?
    • 嗯,一个项目应该属于_to category ,没关系。您可以在每个索引中添加多个伪类别“所有”[“所有”,“特定类别名称”],以支持搜索所有类别)
    • 以及如何从特定类别中获取 albo 子类别?
    • 我猜 sub_category 属于 0 或一个 group_category,对吗?所以在 "all" 旁边,每个属于 "sub category" 的项目应该再添加一个 "group category"。["all", "sub cat", "spec cat"]
    • 自引用模型:Category id: "25cd43a2-bc03-4fa7-977e-df1b6c6a5c65", name: "Nature", description: nil, parent_id: nil, created_at: "2020-02-27 18:06:57", updated_at: "2020-02-27 18:06:57。如果 parent_id 为 nil,则表示它是一个类别,如果有子类别,则表示它是Category id: "6e41c695-8a43-4be5-974b-95fb29e2bb25", name: "Forest", description: nil, parent_id: "25cd43a2-bc03-4fa7-977e-df1b6c6a5c65", created_at: "2020-02-27 18:07:33", updated_at: "2020-02-27 18:07:33">。不知道如何在 elasticsearch-model gem 中处理。
    猜你喜欢
    • 1970-01-01
    • 2015-06-25
    • 2012-04-21
    • 2016-01-18
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多