如何使用 ElasticSearch-Rails 查询 dsl 返回相关关系

Posted

技术标签:

【中文标题】如何使用 ElasticSearch-Rails 查询 dsl 返回相关关系【英文标题】:How can I use ElasticSearch-Rails query dsl to return related relationships 【发布时间】:2015-06-16 08:38:18 【问题描述】:

我是 ElasticSearch 的新手,但需要使用它来返回产品列表。请不要包含引用已弃用的轮胎宝石的答案或旧答案的链接。

宝石文件

ruby '2.2.0'
gem 'rails', '4.0.3'
gem 'elasticsearch-model', '~> 0.1.6'
gem 'elasticsearch-rails', '~> 0.1.6'

我有几个有关系的模型。我包括了以下关系。

模型和关系

product.rb 包括可搜索的

  belongs_to :family
  belongs_to :collection
  has_many :benefits_products
  has_many :benefits, :through => :benefits_products

  def as_indexed_json(options=)
    as_json(
        include: :benefits =>  :only => [ :id, :name ] ,
                  :categories =>  :only => [ :id, :name ]  
    )
  end

collection.rb

  include Searchable

  has_many :products

  def as_indexed_json(options=)
    as_json(
      include: [:products]
    )
  end

family.rb

  include Searchable

  has_many :products

  def as_indexed_json(options=)
    as_json(
      include: [:products]
    )
  end

benefit.rb

  include Searchable

  has_many :benefits_products
  has_many :products, :through => :benefits_products

  def as_indexed_json(options=)
    as_json(
      include: [:products]
    )
  end

Serachable.rb 只是一个关注点,包括所有模型中的弹性搜索和回调

module Searchable
  extend ActiveSupport::Concern

  included do
    include Elasticsearch::Model
    include Elasticsearch::Model::Callbacks

    settings index:  number_of_shards: 1, number_of_replicas: 0  do
      mapping do

        indexes :id, type: 'long'
        indexes :name, type: 'string'
        indexes :family_id, type: 'long'
        indexes :collection_id, type: 'long'
        indexes :created_at, type: 'date'
        indexes :updated_at, type: 'date'

        indexes :benefits, type: 'nested' do
          indexes :id, type: 'long'
          indexes :name, type: 'string'
        end

        indexes :categories, type: 'nested' do
          indexes :id, type: 'long'
          indexes :name, type: 'string'
        end

      end
    end

    def self.search(options=)
      __set_filters = lambda do |key, f|

        @search_definition[:filter][:and] ||= []
        @search_definition[:filter][:and]  |= [f]
      end

      @search_definition = 
        query: 
          filtered: 
            query: 
              match_all: 
            
          
        ,
        filter: 
      

      if options[:benefits]
        f =  term:  "benefits.id": options[:benefits]  

        __set_filters.(:collection_id, f)
        __set_filters.(:family_id, f)
        __set_filters.(:categories, f)
      end

      def as_indexed_json(options=)
        as_json(
          include: :benefits =>  :only => [ :id, :name ] ,
                    :categories =>  :only => [ :id, :name ]  
        )
      end

      if options[:categories]
        ...
      end

      if options[:collection_id]
        ...
      end

      if options[:family_id]
        ...
      end

      __elasticsearch__.search(@search_definition)
    end

  end
end

弹性搜索

我将破折号分开的蛞蝓分为不同的家庭、收藏品和福利。我能够搜索具有特定系列或集合的产品并返回正确的结果。我也可以返回结果以获得一个好处,但它们似乎并不准确。搜索多种好处也会产生奇怪的结果。我想要所有字段搜索的“AND”组合,但我的结果似乎不是“AND”或“OR”的结果。所以这也让我感到困惑。

我应该将什么传递给 Product.search 方法以产生所需的结果?

感谢您提供的任何帮助!

编辑

我现在已经验证了产品上的好处已被索引。我使用了curl -XGET 'http://127.0.0.1:9200/products/_search?pretty=1',它产生了一个如下所示的 json 响应:


  "id":4,
  "name":"product name"
  "family_id":16
  "collection_id":6
  "created_at":"2015-04-13T12:49:42.000Z"
  "updated_at":"2015-04-13T12:49:42.000Z"
  "benefits":[
    "id":2,"name":"my benefit 2",
    "id":6,"name":"my benefit 6",
    "id":7,"name":"my benefit 7"
  ],
  "categories":[
    "id":2,"name":"category 2"
  ]
,
...

如果我想要上面的示例产品,现在我只需要弄清楚如何在 ElasticSearch 中搜索具有 2,6 和 7 优势的产品。我正在专门寻找提交给 elasticsearch #search 方法的语法,以获取嵌套“AND”查询、嵌套查询设置/映射的结果(以确保我没有遗漏任何内容,以及您可以想到的任何其他相关信息你们解决这个问题。

更新

可搜索的问题已更新以反映收到的答案。我翻译了映射 json 对象以适应 elasticsearch-model 语法。当我尝试以类似的方式翻译查询时,我剩下的困惑发生了。

第二次更新

我对 the elasticsearch-rails example app 的 searchable.rb 的大部分关注是基本的。我已更新 searchable.rb 以反映此代码,当我得到结果时,它们不是“AND”执行的结果。当我应用两个好处时,我会从所有具有其中一个好处的产品中得到结果。

【问题讨论】:

您是否在维护名为 id 的外部字段? @monu 如果我理解正确 - 不,这只是所有情况下的 rails 生成的 id 列。如果我误解了,请告诉我。 我添加了一个解决方案,请检查并告诉我。 您可以将术语更改为过滤器部分中的术语吗? 【参考方案1】:

默认情况下,如果您使用动态映射来加载数据,那么 ES 会将嵌套对象创建为平面对象,因此会失去各种嵌套属性之间的关系。为了保持正确的关系,我们可以使用nested objects 或parent-child 关系。

现在我将使用嵌套对象来达到预期的效果:

映射:

PUT /index-3

  "mappings": 
    "products":
      "properties": 
        "id": 
          "type": "long"
        ,
        "name":
          "type": "string"
        ,
        "family_id":
          "type": "long"
        ,
        "collection_id":
          "type": "long"
        ,
        "created_at":
          "type": "date"
        ,
        "updated_at":
          "type": "date"
        ,
        "benefits":
          "type": "nested",
          "include_in_parent": true,
          "properties": 
            "id": 
              "type": "long"
            ,
            "name":
              "type":"string"
            
          
        ,
        "categories":
          "type": "nested",
          "include_in_parent": true,
          "properties": 
            "id":
              "type": "long"
            ,
            "name":
              "type":"string"
            
          
        
      
    
  

如果您发现我已将子对象视为嵌套映射并包含在父对象中。

现在一些示例数据:

PUT /index-3/products/4

  "name":"product name 4",
  "family_id":15,
  "collection_id":6,
  "created_at":"2015-04-13T12:49:42.000Z",
  "updated_at":"2015-04-13T12:49:42.000Z",
  "benefits":[
    "id":2,"name":"my benefit 2",
    "id":6,"name":"my benefit 6",
    "id":7,"name":"my benefit 7"
  ],
  "categories":[
    "id":2,"name":"category 2"
  ]

PUT /index-3/products/5

  "name":"product name 5",
  "family_id":16,
  "collection_id":6,
  "created_at":"2015-04-13T12:49:42.000Z",
  "updated_at":"2015-04-13T12:49:42.000Z",
  "benefits":[
    "id":5,"name":"my benefit 2",
    "id":6,"name":"my benefit 6",
    "id":7,"name":"my benefit 7"
  ],
  "categories":[
    "id":3,"name":"category 2"
  ]

PUT /index-3/products/6

  "name":"product name 6",
  "family_id":15,
  "collection_id":5,
  "created_at":"2015-04-13T12:49:42.000Z",
  "updated_at":"2015-04-13T12:49:42.000Z",
  "benefits":[
    "id":5,"name":"my benefit 2",
    "id":55,"name":"my benefit 6",
    "id":7,"name":"my benefit 7"
  ],
  "categories":[
    "id":3,"name":"category 2"
  ]

现在是查询部分:

GET index-3/products/_search

  "query": 
    "filtered": 
      "query": 
        "match_all": 
      ,
      "filter": 
        "terms": 
          "benefits.id": [
            5,6,7
          ],
          "execution": "and"
        
      
    
  

这会产生以下结果:


   "took": 1,
   "timed_out": false,
   "_shards": 
      "total": 1,
      "successful": 1,
      "failed": 0
   ,
   "hits": 
      "total": 1,
      "max_score": 1,
      "hits": [
         
            "_index": "index-3",
            "_type": "products",
            "_id": "5",
            "_score": 1,
            "_source": 
               "name": "product name 5",
               "family_id": 16,
               "collection_id": 6,
               "created_at": "2015-04-13T12:49:42.000Z",
               "updated_at": "2015-04-13T12:49:42.000Z",
               "benefits": [
                  
                     "id": 5,
                     "name": "my benefit 2"
                  ,
                  
                     "id": 6,
                     "name": "my benefit 6"
                  ,
                  
                     "id": 7,
                     "name": "my benefit 7"
                  
               ],
               "categories": [
                  
                     "id": 3,
                     "name": "category 2"
                  
               ]
            
         
      ]
   

在查询时,我们必须使用带有“和执行”的术语过滤器,因此它只会检索包含所有术语的文档。

【讨论】:

感谢您的回复。我更新了我的 Searchable.rb 以反映索引。我仍然对如何翻译查询以适应弹性 search-rails dsl 感到有些困惑,如此处所示github.com/elastic/elasticsearch-rails/tree/master/… 对不起,我在问题中的错误,我已经更新它更准确。我还更新了 searchable.rb 以反映我当前的进度。 我给了你赏金,因为我知道你的答案是正确的。赏金即将到期,我不希望由于我措辞不当的问题而浪费您的努力。如果您对最新更新有任何见解,我希望您能听到。如果没有,我仍然感谢您的帮助以及我因此取得的进展。谢谢!

以上是关于如何使用 ElasticSearch-Rails 查询 dsl 返回相关关系的主要内容,如果未能解决你的问题,请参考以下文章

如果加入条件,我该如何解决。如果使用字符串连接,我如何使用

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?