我正在使用 ElasticSearch 和 tire gem 来支持搜索 我网站的功能。我无法弄清楚如何映射和 查询数据以获得我需要的结果。
相关代码如下。我将在下面解释所需的结果 好吧。
# models/product.rb
class Product < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
has_many :categorizations
has_many :categories, :through => :categorizations
has_many :product_traits
has_many :traits, :through => :product_traits
mapping do
indexes :id, type: 'integer'
indexes :name, boost: 10
indexes :description, analyzer: 'snowball'
indexes :categories do
indexes :id, type: 'integer'
indexes :name, type: 'string', index: 'not_analyzed'
end
indexes :product_traits, type: 'string', index: 'not_analyzed'
end
def self.search(params={})
out = tire.search(page: params[:page], per_page: 12, load: true) do
query do
boolean do
must { string params[:query], default_operator: "OR" } if params[:query].present?
must { term 'categories.id', params[:category_id] } if params[:category_id].present?
# if we aren't browsing a category, search results are "drill-down"
unless params[:category_id].present?
must { term 'categories.name', params[:categories] } if params[:categories].present?
end
params.select { |p| p[0,2] == 't_' }.each do |name,value|
must { term :product_traits, "#{name[2..-1]}##{value}" }
end
end
end
# don't show the category facets if we are browsing a category
facet("categories") { terms 'categories.name', size: 20 } unless params[:category_id].present?
facet("traits") {
terms :product_traits, size: 1000 #, all_terms: true
}
# raise to_curl
end
# process the trait facet results into a hash of arrays
if out.facets['traits']
facets = {}
out.facets['traits']['terms'].each do |f|
split = f['term'].partition('#')
facets[split[0]] ||= []
facets[split[0]] << { 'term' => split[2], 'count' => f['count'] }
end
out.facets['traits']['terms'] = facets
end
out
end
def to_indexed_json
{
id: id,
name: name,
description: description,
categories: categories.all(:select => 'categories.id, categories.name, categories.keywords'),
product_traits: product_traits.includes(:trait).collect { |t| "#{t.trait.name}##{t.value}" }
}.to_json
end
end
正如您在上面看到的,我正在对数据进行一些前/后处理 到/从elasticsearch为了得到我想要的东西 'product_traits' 字段。这就是我感觉不对的地方 问题产生。
我有一个很大的产品目录,每个产品都有一些“特征”,例如 作为颜色、 Material 和品牌。由于这些特征如此多样,我 对数据建模以包含与产品相关的特征模型 通过 ProductTrait 模型建立模型,该模型保存特征的值 给定的产品。
第一个问题是:如何创建 Elasticsearch 映射到索引 这些特质合适吗?我假设这涉及嵌套类型,但我 无法充分理解文档以弄清楚。
第二个问题:我希望分面以组的形式返回(在
我在 search
方法末尾处理它们的方式
上面)但计数反射(reflect)了有多少匹配没有
考虑到当前为每个特征选择的值。 对于
示例:如果用户搜索“Glitter”然后单击链接
对应于“蓝色”方面,我想要所有“颜色”方面
保持可见并显示与查询结果对应的计数
没有“蓝色”滤镜。我希望这是一个很好的解释,
抱歉,如果需要更多说明。
最佳答案
如果你将你的特征索引为:
[
{
trait: 'color',
value: 'green'
},
{
trait: 'material',
value: 'plastic'
}
]
这将在内部被索引为:
{
trait: ['color', 'material' ],
value: ['green', 'plastic' ]
}
这意味着您只能查询具有值为“color”的 trait
和值为 green
的 value
的文档。 trait
和 value
之间没有关系。
您有几种选择来解决这个问题。
作为单个术语
第一个你已经在做了,这是一个很好的解决方案,即将特征存储为单个术语,如:
['color#green`','material#plastic']
作为对象
另一种方法(假设您的特征名称数量有限)是将它们存储为:
{
traits: {
color: 'green',
material: 'plastic'
}
}
然后您可以针对 traits.color
或 traits.material
运行查询。
嵌套
如果你想保留你的数组结构,那么你可以使用 nested type例如:
{
"mappings" : {
"product" : {
"properties" : {
... other fields ...
"traits" : {
"type" : "nested",
"properties" : {
"trait" : {
"index" : "not_analyzed",
"type" : "string"
},
"value" : {
"index" : "not_analyzed",
"type" : "string"
}
}
}
}
}
}
}
每个特征/值对都将在内部作为单独(但相关)的文档进行索引,这意味着特征与其值之间存在关系。你需要使用 nested queries或 nested filters查询它们,例如:
curl -XGET 'http://127.0.0.1:9200/test/product/_search?pretty=1' -d '
{
"query" : {
"filtered" : {
"query" : {
"text" : {
"name" : "my query terms"
}
},
"filter" : {
"nested" : {
"path" : "traits",
"filter" : {
"and" : [
{
"term" : {
"trait" : "color"
}
},
{
"term" : {
"value" : "green"
}
}
]
}
}
}
}
}
}
'
组合分面、过滤和嵌套文档
您声明,当用户过滤 color == green
时,您只想在 color == green
处显示结果,但您仍想显示计算所有颜色。
为此,您需要对 search API 使用 filter
参数而不是过滤查询。过滤查询在计算构面之前过滤掉结果。 filter
参数在计算构面后应用于查询结果。
这是一个示例,其中最终查询结果仅限于 color == green
的文档,但 facets 是针对所有颜色计算的:
curl -XGET 'http://127.0.0.1:9200/test/product/_search?pretty=1' -d '
{
"query" : {
"text" : {
"name" : "my query terms"
}
},
"filter" : {
"nested" : {
"path" : "traits",
"filter" : {
"and" : [
{
"term" : {
"trait" : "color"
}
},
{
"term" : {
"value" : "green"
}
}
]
}
}
},
"facets" : {
"color" : {
"nested" : "traits",
"terms" : { "field" : "value" },
"facet_filter" : {
"term" : {
"trait" : "color"
}
}
}
}
}
'
关于ruby - 如何使用 ElasticSearch 映射/查询这些数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12500461/