Rails Elasticsearch - 多个过滤条件

时间:2015-11-27 15:28:58

标签: ruby-on-rails elasticsearch filter

我有一个模型广告系列,可以由类型的用户创建:" NonProfit"和"个人"。

现在,我想搜索由NonProfit或仅限个人或其中任何一个创建的广告系列。

这是我的模特:

class Campaign < ActiveRecord::Base
after_commit lambda { __elasticsearch__.index_document  },  on: :create
after_commit lambda { __elasticsearch__.update_document },  on: :update

belongs_to :user

enum status: { waiting: 0, approved: 1, disapproved: 2, expired: 3, canceled: 4, draft: 5, published: 6}


def user_type
   self.user.rolable_type
end

def as_json(options={})
  super(:only => [:id, :status, :title, :description],
        :methods => [:user_type])
end

settings index: {
number_of_shards: 1,
analysis: {
  filter: {
    trigrams_filter: {
      type: 'ngram',
      min_gram: 2,
      max_gram: 10
    },
    content_filter: {
      type: 'ngram',
      min_gram: 4,
      max_gram: 20
    }
  },
  analyzer: {
    index_trigrams_analyzer: {
      type: 'custom',
      tokenizer: 'standard',
      filter: ['lowercase', 'trigrams_filter', 'asciifolding']
    },
    search_trigrams_analyzer: {
      type: 'custom',
      tokenizer: 'whitespace',
      filter: ['lowercase']
    },
    english: {
      tokenizer: 'standard',
      filter: ['standard', 'lowercase', 'content_filter']
    },
    czech: {
      tokenizer: 'standard',
      filter: ['standard','lowercase','content_filter', 'asciifolding']
    }
  }
}
} do
mappings dynamic: 'false' do
  indexes :status, type: 'string'
  indexes :user_type, type: 'string'
  indexes :en_title, index_analyzer: 'english', search_analyzer: 'english'
  indexes :ma_title, index_analyzer: 'czech', search_analyzer: 'czech'
  indexes :cs_title, index_analyzer: 'czech', search_analyzer: 'czech'
  indexes :en_description, index_analyzer: 'english', search_analyzer: 'english'
  indexes :ma_description, index_analyzer: 'czech', search_analyzer: 'czech'
  indexes :cs_description, index_analyzer: 'czech', search_analyzer: 'czech'
end
end

  def as_indexed_json(options={})
{ id: id,
  status: status,
  user_type: user_type,
  ma_title: ma_title,
  cs_title: cs_title,
  en_title: en_title,
  ma_description: ma_description,
  cs_description: cs_description,
  en_description: en_description  
}
  end

   def self.search(query, user_type)
__elasticsearch__.search(
  {
    query: {
      filtered: {
        query: {
          multi_match: {
            query: query,
            fields: ['ma_title^10', 'cs_title^10', 'en_title^10', 'ma_description', 'cs_description', 'en_description']
          }
        },
        filter: {
          term: {
            status: "published"               
          },
          term: {
            user_type: user_type
          }
        }
      }
    }       
  }
)
 end

end

我的控制器看起来像这样:

Campaign.search(params[:q], 'NonProfit') # to search only NonProfit campaigns
Campaign.search(params[:q], 'Individual') # to search only Individual campaigns
Campaign.search(params[:q], ['NonProfit','Individual']) # to search any of the campaigns

但是我总是得到0结果。当我删除过滤词“user_type&#39;”时,我的工作正常。我没有成功地让user_type过滤器术语按预期工作。

任何想法,如何让它工作? 谢谢,米罗斯拉夫

UPDATE 1(过滤器user_type仍无效 - 0结果):

def as_json(options={})
  super(:only => [:id, :status, :title, :description],
        :methods => [:user_type]
     #   :include => {
     #     :employers => {:only => [:title]},
     #     :roles => {:only => [:name]}
     #   }
  )
end

settings index: {
number_of_shards: 1,
analysis: {
  filter: {
    trigrams_filter: {
      type: 'ngram',
      min_gram: 2,
      max_gram: 10
    },
    content_filter: {
      type: 'ngram',
      min_gram: 4,
      max_gram: 20
    }
  },
  analyzer: {
    index_trigrams_analyzer: {
      type: 'custom',
      tokenizer: 'standard',
      filter: ['lowercase', 'trigrams_filter', 'asciifolding']
    },
    search_trigrams_analyzer: {
      type: 'custom',
      tokenizer: 'whitespace',
      filter: ['lowercase']
    },
    english: {
      tokenizer: 'standard',
      filter: ['standard', 'lowercase', 'content_filter']
    },
    czech: {
      tokenizer: 'standard',
      filter: ['standard','lowercase','content_filter', 'asciifolding']
    }
  }
}
} do
mappings dynamic: 'false' do
  indexes :status, type: 'string', index: 'not_analyzed'
  indexes :user_type, type: 'string', index: 'not_analyzed'
  indexes :en_title, index_analyzer: 'english', search_analyzer: 'english'
  indexes :ma_title, index_analyzer: 'czech', search_analyzer: 'czech'
  indexes :cs_title, index_analyzer: 'czech', search_analyzer: 'czech'
  indexes :en_description, index_analyzer: 'english', search_analyzer: 'english'
  indexes :ma_description, index_analyzer: 'czech', search_analyzer: 'czech'
  indexes :cs_description, index_analyzer: 'czech', search_analyzer: 'czech'
end
end

def as_indexed_json(options={})
{ id: id,
  status: status,
  ma_title: ma_title,
  cs_title: cs_title,
  en_title: en_title,
  ma_description: ma_description,
  cs_description: cs_description,
  en_description: en_description,
  :methods => [:user_type]
}
end




def self.search(query, user_type)
__elasticsearch__.search(
  {
    query: {
      filtered: {
        query: {
          multi_match: {
            query: query,
            fields: ['ma_title^10', 'cs_title^10', 'en_title^10', 'ma_description', 'cs_description', 'en_description']
          }
        },
        filter: {
          bool: {
            must: [
              {
                term: {
                  status: "published"
                }
              },
              {
                terms: {
                  user_type: user_type
                }
              }
            ]
          }
        }
      }
    }       
  }
)
end

1 个答案:

答案 0 :(得分:1)

您需要为mapping字段statususer_type添加"index" : "not_analyzed"。由于您未指定任何分析器ES,因此对这些字段使用standard analyzer

mappings dynamic: 'false' do
  indexes :status, type: 'string', index : 'not_analyzed' <--- here
  indexes :user_type, type: 'string', index : 'not_analyzed' <--- here

如果您需要使用term过滤器,则需要确保完全匹配,因为term queries不执行任何分析。

同样适用于Campaign.search(params[:q], ['NonProfit','Individual']) # to search any of the campaigns,您需要在搜索多个值时使用terms filter

编辑 条款查询

条款查询需要值数组

Campaign.search(params[:q], ['NonProfit'])

试试这个

{
   "terms": {
      "user_type": ['NonProfit']
   }
 }

我希望这会有所帮助。