改写为:
在我的项目中,我有图像。每个图像都有5个范围[1,10]的标签。我使用Elasticsearch上传这些标签:
我将这些文档加载到索引“my_project”中的elasticsearch,类型为“img”:
curl -XPUT 'http://localhost:9200/my_project/img/1' -d '
{"tags": [1,4,6,7,9]}
'
我上传的其他示例文档:
{"tags": [1,4,6,7]}
{"tags": [2,3,5,6]}
{"tags": [1,2,3,8]}
在我的应用程序中,向量更长,但具有固定数量的唯一元素。我有20M这些文件。
现在我想找到给定矢量的类似文档。当矢量具有更常见的标签时,矢量更相似。因此,例如,我想找到整数向量[1,2,3,7]
的大多数类似文档。最佳匹配应该是最后一个示例文档{"tags": [1,2,3,8]}
,因为它们在其标记[1,2,3]
中共享3个常见值,比其他任何向量更常见的值。
所以这是我的问题。如果我使用上面的CURL命令上传文档,我会得到这个映射:
{
"my_project" : {
"mappings" : {
"img" : {
"properties" : {
"tags" : {
"type" : "string"
}
}
}
}
}
}
但我认为正确的映射应该使用整数而不是字符串。如何为此类数据制作正确的显式映射?
现在我想用上面的相似度算法搜索文档。如何使用上面解释的相似度算法获得上述类型的100个最相似的文档?如果我将这些向量转换为具有空格分隔数字的字符串,我将能够使用带有for语句的布尔查询进行此搜索,但我认为使用整数数组应该更快。你能告诉我,我怎样才能为elasticsearch构建搜索查询?
我现在使用的基本解决方案是将整数数组转换为字符串。所以我将文件保存为:
curl -XPUT 'http://localhost:9200/my_project/img/1' -d '
{"tags": "1 4 6 7 9"}
'
然后基本上搜索字符串"1 2 3"
。虽然这在某种程度上起作用,但我认为将整数数组保存为整数数组而不是字符串会更正确和更快。是否可以像使用整数数组一样使用elasticsearch中的整数数组?也许我的字符串方法是最好的,不能/不必在elasticsearch中明确使用整数数组。
答案 0 :(得分:7)
您可以使用function score query公式Euclidian distance来获得所需内容。
删除当前的映射并索引文档:
curl -XPUT 'http://localhost:9200/my_project/img/1' -d '
{
"tags": {
"tag1": 1,
"tag2": 4,
"tag3": 6,
"tag4": 7
}
}'
curl -XPUT 'http://localhost:9200/my_project/img/2' -d '
{
"tags": {
"tag1": 2,
"tag2": 3,
"tag3": 5,
"tag4": 6
}
}'
curl -XPUT 'http://localhost:9200/my_project/img/3' -d '
{
"tags": {
"tag1": 1,
"tag2": 2,
"tag3": 3,
"tag4": 8
}
}'
停止Elasticsearch并在$ES_HOME/config/scripts
中创建名为“euclidian_distance.mvel”的脚本文件并添加此脚本。
_score * pow(sqrt(pow(doc['tags.tag1'].value - param1, 2)) + sqrt(pow(doc['tags.tag2'].value - param2, 2)) + sqrt(pow(doc['tags.tag3'].value - param3, 2)) + sqrt(pow(doc['tags.tag4'].value - param4, 2)), -1)
重新启动Elastisearch并运行此查询:
curl -XPOST 'http://localhost:9200/my_project/' -d '
{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"script_score": {
"script": "euclidian_distance",
"params": {
"param1": 1,
"param2": 2,
"param3": 3,
"param4": 7
}
}
}
}
}
将首先返回值为1,2,3,8
的标记对象。
答案 1 :(得分:2)
我将从去年的Elasticsearch邮件列表中看一下去年的讨论。另一个ES用户试图完成你想要做的事情,匹配数组元素并按相似性排序。在他的情况下,他的阵列成员是“一个”,“两个”,“三个”等,但它几乎相同:
http://elasticsearch-users.115913.n3.nabble.com/Similarity-score-in-array-td4041674.html
讨论中提到的问题并不能解决您想要开箱即用的问题。你使用数组成员的方法(字符串或整数,我认为两者都会没问题)会让你接近,但可能会与你想要达到的目标有所不同。原因是Elasticsearch(和Lucene / Solr)中的默认相似性评分机制是TF / IDF:http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/relevance-intro.html
TF / IDF可能非常接近,根据用例可能会给你相同的结果,但不能保证这样做。一个非常频繁出现的标签(假设“1”的频率是“2”的两倍)会改变每个术语的权重,这样你就可能得不到你想要的东西了。
如果您需要精确的评分/相似度算法,我相信您需要自定义评分。正如您所发现的那样,自定义评分脚本无法很好地扩展,因为该脚本将针对每个文档运行,因此它不会太快开始,并且会以线性方式在响应时间内衰减。
我个人可能会尝试使用Elasticsearch提供的一些相似性模块,比如BM25:
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/index-modules-similarity.html