jav*_*ali 2 lucene elasticsearch elasticsearch-plugin
在使用 Elasticsearch 制作的搜索引擎中,考虑用户点击结果项目以提高具有更多用户印象的文档分数的最佳解决方案是什么?
是否有任何可以使用的工具或插件,还是应该从头开始编写?
该解决方案预计会像谷歌一样考虑以下内容:
如果你正在使用 rails/ruby 开发你的 API,你可以看看searchkick,它几乎可以完成这项工作,通过使搜索解决方案每天更智能,使用更多。
现在,如果你不在轨道上或者你想开发自己的内部实现,这里有一些我这边的架构建议。
让我们首先从基本概述、关键模块、缺点和针对解决方案中的缺点调整架构。
你会需要
1) 评分算法,您可以在其中定义公式的等式,该公式将为每个文档生成分数。让我们考虑你提到的参数
a) 每个文档被显示的次数 b) 文档被点击的次数。c) 查询要搜索的文档。
现在你没有提到 a) 和 b) 如何适应当前的上下文。我会假设一个更简单的,但如果你想构建一个非常先进的智能解决方案,我也会将 a) b) 与 c) 结合起来。例如 - 文档针对给定关键字出现了多少次。像我一样搜索“雪地靴”应该只在查询或多或少像“雪地靴”时才考虑这个(出现次数/点击次数),而不是所有情况。其中“snow boots”可以被分解为带有关键字顺序近似的以下元的关键字。
{
"keyword": "snow",
"document_ids": [3, 5, 6, 8],
"document_ids_views": [{
"doc_id": 3,
"views ": 110,
"clicks": 560
}, {
"doc_id": 5,
"views": 100,
"clicks": 78
}, {
"doc_id": 6,
"views": 100,
"clicks": 120
}, {
"doc_id": 3,
"views": 100,
"clicks": 465
}]
}
{
"keyword": "boots",
"document_ids": [3, 5, 6, 8],
"document_ids_views": [{
"doc_id": 3,
"views ": 100,
"clicks": 56
}, {
"doc_id": 5,
"views": 100,
"clicks": 78
}, {
"doc_id": 6,
"views": 100,
"clicks": 120
}, {
"doc_id": 3,
"views": 100,
"clicks": 465
}]
}
Run Code Online (Sandbox Code Playgroud)
以上是针对每个关键字存储在单独数据库中的汇总数据。
像这样,我每天都会在单独的数据存储中构建统计数据的元数据,比如 mongo。如果我的元数据中已经有“snow”并且新的查询带有这个关键字,我将更新相同的元文档。
现在我想讨论缺点以及为什么我选择将它们保存在单独的数据库中而不是将它们附加到 elasticsearch 文档中。
我不想在每次触发新查询以更新弹性文档中的点击计数和查看计数时都受到 elasticsearch 集群的影响,因为我知道更新非常 I/O,并且具有倒排索引合并。
现在为了弥补这个缺点,我将有一个每天或每天两次的批处理作业,将这些元信息以弹性方式移植到每个文档中。我会用这个新的元信息重建整个集群,并将别名从旧索引移动到新索引,而没有任何停机时间。
现在要将此信息关联或添加到弹性文档,我将使用父子文档关系将弹性文档与与此相关联的关键字映射。
所以我的基本父文档和子文档看起来像
父文件
PUT /index/type/3
{
"name": "Reebok shoes",
"category": "snow boots",
"price": 120
}
Run Code Online (Sandbox Code Playgroud)
子文件
PUT /index/type_meta/1?parent=3
{
"keyword": "boots",
"document_id": 3,
"doc_id": 3,
"views ": 100,
"clicks": 56
}
PUT /index/type_meta/1?parent=3
{
"keyword": "snow",
"document_id": 3,
"doc_id": 3,
"views ": 110,
"clicks": 560
}
Run Code Online (Sandbox Code Playgroud)
上面的父子文档几乎解释了我如何为每个文档的搜索统计构建元数据。
到目前为止,我们已经构建了一个非常智能的解决方案来收集搜索统计的事件数据,并成功地将它们与弹性中的每个文档相关联。
让我们开始在这里查看评分查询 -
我不会在这里深入设计评分算法,但我将更多地实现查询,该查询可以根据视图、与关键字关联的点击以及与关键字的相关性对文档进行评分。
现在我可以选择在名称上比在类别上给予更多的权重。从您的用例角度来看,这就是全部,我不会深入为您设计评分公式。
{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"boost": "5",
"functions": [{
"filter": {
"match": {
"name": "snow"
}
},
"random_score": {},
"weight": 200
}, {
"filter": {
"match": {
"name": "boots"
}
},
"weight": 200
}, {
"filter": {
"match": {
"category": "snow"
}
},
"random_score": {},
"weight": 100
}, {
"filter": {
"match": {
"category": "boots"
}
},
"weight": 100
}, {
"filter": {
"query": {
"has_parent": {
"type": "type_meta",
"query": {
"match": {
"keyword": "snow"
}
}
}
}
},
"script_score": {
"script": {
"lang": "painless",
"inline": "_score + 20*doc['clicks'].value + 40 * doc['views].value"
}
}
}, {
"filter": {
"query": {
"has_parent": {
"type": "type_meta",
"query": {
"match": {
"keyword": "boots"
}
}
}
}
},
"script_score": {
"script": {
"lang": "painless",
"inline": "_score + 20*doc['clicks'].value + 40 * doc['views].value"
}
}
}],
"score_mode": "max",
"boost_mode": "multiply"
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以你可以使用类似上面的查询,我刚刚选择了一个非常简单的公式,每个子句都有演示提升参数,这个查询可以在实现高级评分算法后进行重构。
脚本评分功能在这里很重要,因为我首先根据单个父文档的搜索关键字过滤子文档,然后使用脚本评分使用点击和查看计数来影响我的整体文档评分。
现在这是我希望在我的项目中实施的一种解决方案,我愿意为我的解决方案提出建议和改进。
请分享您的建议和改进。
希望这有助于谢谢