我想确保我以正确的方式思考这个问题。我正在尝试使用 Elasticsearch 自动完成嵌套项目。我有一个列表,一个列表有很多项目。我想使用 ES 返回匹配的项目名称,如果它们存在于当前列表中,则通过传递列表名称和项目名称以在 Elasticsearch 中搜索,对它们进行更强烈的加权。
理论上我可以简单地单独索引项目并以这种方式搜索它们,但我宁愿通过列表文档搜索它们,以便我可以控制相关性。
我不知道如何返回与放入的内容几乎匹配的项目。这是我的设置...(使用 Elasticsearch-Rails 和 Elasticsearch-Model 的 Rails)
索引映射:
settings :index => { :number_of_shards => 1 } do
mapping :dynamic => 'false' do
indexes :private, :type => 'boolean'
indexes :name, :type => 'string'
indexes :slug, :type => 'string'
indexes :bookmarks_count , :type => 'integer'
indexes :item_names, :type => 'string'
indexes :up_count, :type => 'integer'
indexes :permalink, :type => 'string'
indexes :sub_text, :type => 'string'
indexes :title_text, :type => 'string'
indexes :creator_name, :type => 'string'
indexes :creator_avatar, :type => 'string'
indexes :cover_image, :type => 'string'
indexes :items, :type => "nested" do
indexes :name
indexes :description
indexes :image_url
indexes :link
end
end
end
JSON:
def as_indexed_json(options = {})
as_json(:include => [:items, :tags],
:methods => [:permalink, :sub_text, :title_text, :icon_url, :item_names, :creator_name, :creator_avatar, :cover_image]
)
end
这是我调用的搜索方法:
def item_typeahead_search(list_name, search_query, page = 1, per = 5)
wildcarded_query = "*#{search_query}*"
::List.search(item_typeahead_querystring(list_name, wildcarded_query)).per(per).page(page)
end
def item_typeahead_querystring(list_name, query_string)
{
:query => {
:bool => {
:should => [
{ :match => { :name => list_name }},
{
:nested => {
:path => "items",
:score_mode => "max",
:query => {
:bool => {
:must => [
{ :match => { "items.name" => query_string }}
]
}}}}
]
}}}
end
这是一个示例查询...
results = List.item_typeahead_search("try me", "crazy glue")
这是结果...
=> #<Elasticsearch::Model::Response::Result:0x007fb8f25c5208
@result=
{"_index"=>"lists",
"_type"=>"list",
"_id"=>"54504855f29a589a2700003b",
"_score"=>8.652843,
"_source"=>
{"_id"=>"54504855f29a589a2700003b",
"bookmarks_count"=>0,
"carousel"=>nil,
"cid"=>"5j18j8aor",
"content_source_name"=>nil,
"content_source_url"=>nil,
"created_at"=>"2014-10-29T01:52:21Z",
"description"=>nil,
"down_count"=>0,
"down_voters"=>[],
"intralist_id"=>"545057f7692a270e03000266",
"items"=>
[{"_id"=>"545048d5f29a589a27000044",
"created_at"=>"2014-10-29T01:54:29Z",
"description"=>nil,
"down_count"=>0,
"down_voters"=>[],
"image_small_url"=>nil,
"image_thumb_url"=>nil,
"image_url"=>nil,
"link"=>nil,
"name"=>"a swiss army knife",
"order"=>nil,
"picture"=>nil,
"up_count"=>0,
"up_voters"=>[],
"updated_at"=>"2014-10-29T01:54:29Z",
"vote_count"=>0},
{"_id"=>"545048d5f29a589a27000045",
"created_at"=>"2014-10-29T01:54:29Z",
"description"=>nil,
"down_count"=>0,
"down_voters"=>[],
"image_small_url"=>nil,
"image_thumb_url"=>nil,
"image_url"=>nil,
"link"=>nil,
"name"=>"duct tape",
"order"=>nil,
"picture"=>nil,
"up_count"=>0,
"up_voters"=>[],
"updated_at"=>"2014-10-29T01:54:29Z",
"vote_count"=>0},
{"_id"=>"545048d5f29a589a27000046",
"created_at"=>"2014-10-29T01:54:29Z",
"description"=>nil,
"down_count"=>0,
"down_voters"=>[],
"image_small_url"=>nil,
"image_thumb_url"=>nil,
"image_url"=>nil,
"link"=>nil,
"name"=>"Crazy glue",
"order"=>nil,
"picture"=>nil,
"up_count"=>0,
"up_voters"=>[],
"updated_at"=>"2014-10-29T01:54:29Z",
"vote_count"=>0},
{"_id"=>"545048d5f29a589a27000047",
"created_at"=>"2014-10-29T01:54:29Z",
"description"=>nil,
"down_count"=>0,
"down_voters"=>[],
"image_small_url"=>nil,
"image_thumb_url"=>nil,
"image_url"=>nil,
"link"=>nil,
"name"=>"a nut",
"order"=>nil,
"picture"=>nil,
"up_count"=>0,
"up_voters"=>[],
"updated_at"=>"2014-10-29T01:54:29Z",
"vote_count"=>0}],
"name"=>"try me",
"parent_list_creator"=>nil,
"parent_list_id"=>nil,
"private"=>false,
"promoted"=>false,
"slug"=>"things-for-fixing-anything",
"up_count"=>0,
"up_voters"=>[],
"updated_at"=>"2014-10-29T02:59:03Z",
"user_id"=>"543809c4b64c402d6a000003",
"vote_count"=>0,
"permalink"=>"/lists/things-for-fixing-anything",
"sub_text"=>"List - created by: CreepyTimes",
"title_text"=>"try me",
"icon_url"=>"",
"item_names"=>"a swiss army knife duct tape Crazy glue a nut",
"creator_name"=>"CreepyTimes",
"creator_avatar"=>"https://blahblah.com/uploads/profile/image/543809c4b64c402d6a000004/thumb__old_",
"cover_image"=>nil,
"tags"=>[]}}>
因此,我将“疯狂的胶水”视为列表中的一个项目,但它是众多项目之一 - 当有人开始输入项目名称时,我可以在这里开箱即用地用于自动完成目的
有没有办法使用嵌套查询、过滤器或其他东西来做我想做的事情?对 Elasticsearch 来说相对较新,所以我可以在最终解决方案上使用一些帮助。如果我没有以正确的方式考虑这一点而应该简单地索引项目,我也可以这样做,但只是好奇是否有办法使这项工作!
编辑 - 这是进入 Elasticsearch 的查询:
#<Elasticsearch::Model::Searching::SearchRequest:0x007fc555032218
@definition=
{:index=>"lists",
:type=>"list",
:body=>
{:query=>
{:bool=>
{:should=>
[{:match=>{:name=>"try me"}},
{:nested=>{:path=>"items", :score_mode=>"max", :query=>{:bool=>{:must=>[{:match=>{"items.name"=>"*crazy glue*"}}]}}}}]}}},
:size=>5,
:from=>0},
@klass=[PROXY] List,
@options={}>>