Rails和Elasticsearch - 过滤器,权重和统计信息

时间:2016-06-08 02:01:30

标签: ruby-on-rails elasticsearch mongoid

考虑以下模型

class MyModel # `Employee` used in concrete examples
  field :field1 # company_name used in concrete examples
  field :field2 # job_name used in concrete examples
  scope: filter1 # non_retired
  scope: filter2
end
  • 我需要过滤/执行命名搜索查询,例如按非犯罪过滤
  • 我需要对某些字段进行加权(例如,对某些字段赋予3倍的重要性)
  • 我需要根据结果获取统计信息(例如,不仅仅是前10个分页结果),例如,聚合company_names(我已经使用了代码,但是我遇到了问题)获得“总”结果ID。

我把所有这些放在一起有问题。从Rails elasticsearch - named scope search开始,我了解到我需要将ID直接提供给Elasticsearch。

def search_by_id(query, type, ids, options = {})
  self.weighted_search(query, options.deep_merge({
    query: {
      multi_match: {
        filter: {
          ids: {
            values: ids
          }.tap do |filter|
          filter[:type] = type if type
        end
        }
      }
    }
  }))
end

def weighted_search(query, options = {})
  self.__elasticsearch__.search(
    {
      query: {
        multi_match: {
          query: query,
          fields: [
            "company_name^3",
            "job_name^2",
          ],
          # strategy: 'leap_frog_filter_first'
          # PROBLEM :cannot use this strategy on multi_match ?
        }
      }
    }.deep_merge(options)
  )
end

这会产生BadRequest错误,并带有以下说明

  

[400] {“error”:{“root_cause”:[{“type”:“query_parsing_exception”,“reason”:“[match] query不支持[$ oid]

我不明白这个错误......我无法按ID过滤?

然后,假设我有这个工作,如何提取与ElasticSearch匹配的id的子集?

search = MyModel.search('query')
search.total_results # => 81
search.records.count # => 10

但我需要获得所有81个ID以便我可以执行一些统计(即汇总公司名称,我已经有一些代码可以工作,但现在我只得到前10个结果汇总...)

1 个答案:

答案 0 :(得分:0)

好的,这是我目前的解决方案(我不喜欢,因为它击中了数据库很多)

  • 仅使用MongoDB命名范围来过滤记录,并拔出其ID

    ids = @my_model_filtered.pluck(:id)
    
  • 将结果ID发送给ES,并使用特定字段的提升进行评分搜索

    def search_by_id(query, type, ids, options = {})
      self.weighted_search(query, options.deep_merge({
        query: {
          filtered: {
            filter: {
              ids: {
                values: ids.map(&:to_s)
              }.tap do |filter|
              filter[:type] = type if type
            end
            }
          }
        }
      }))
    end
    
    def weighted_search(query, options = {})
      self.__elasticsearch__.search(
        {
          query: {
            filtered: {
              query: {
                multi_match: {
                  query: query,
                  fields: [
                    "company_name^3",
                    "job_name^2",
                    "xxx"
                  ],
                  type: "most_fields"
                }
              }
            }
          }
     }.deep_merge(options)
      )
     end
    
  • 使用Elasticsearch提供的ID列表对MongoDB数据库进行其他信息提取(聚合等)

    @response = @searching.search_by_id(@query, @searchable_type, ids).per(10000) # setting a high per number so ES returns all IDs
    @all_records = @response.records.records
    
    # Further processing
    @all_records.map_reduce(...)