2013-07-08 75 views
7

我想确定在弹性搜索中索引文档的最佳方式。我有一个Doc文档,里面有一些字段:如何在弹性搜索中避免使用嵌套类型的交叉对象搜索行为

Doc 
    created_at 
    updated_at 
    field_a 
    field_b 

但是Doc还会有一些特定于个人用户的字段。例如,field_x对于用户1将具有值“A”,对于用户2,field_x将具有值“B”。对于每个doc,将会有非常有限数量的用户(通常为2,高达〜10)。当用户在field_x上搜索时,他们必须搜索属于它们的值。我一直在ES中探索嵌套类型。

Doc 
    created_at 
    updated_at 
    field_x: [{ 
    user: 1 
    field_x: A 
    },{ 
    user: 2 
    field_x: B 
    }] 

当用户1在field_x上搜索值'A'时,该文档应该会导致命中。但是,当用户1按值'B'搜索时,它不应该。

然而,according to the docs

索引的文档中出现的几个 时间内的物体时,其中一个问题是,“交叉对象”搜索匹配会发生

是否有办法为了避免嵌套类型的这种行为或我应该探索另一种类型?

关于执行此类查询的其他信息将非常有价值。通过阅读文档,它指出嵌套查询在性能方面与常规查询相比并没有太大差别。如果任何人有真正的经验,我很乐意听到它。

回答

5

嵌套类型就是你要找的东西,不要太担心表现。

之前索引您的文档,您需要设置映射文档:

curl -XDELETE localhost:9200/index 
curl -XPUT localhost:9200/index 
curl -XPUT localhost:9200/index/type/_mapping -d '{ 
    "type": { 
     "properties": { 
      "field_x": { 
       "type": "nested", 
       "include_in_parent": false, 
       "include_in_root": false, 
       "properties": { 
        "user": { 
         "type": "string" 
        }, 
        "field_x": { 
         "type": "string", 
         "index" : "not_analyzed" // NOTE* 
        } 
       } 
      } 
     } 
    } 
}' 

* 注:如果你的领域的确不包含如“A”和“B”仅单一字母,你不”不想分析该字段,否则弹性搜索将删除这些单数字母“单词”。 如果这只是您的示例,并且在您的真实文档中搜索正确的词语,请删除此行并让elasticsearch分析该字段。

然后,索引你的文件:

curl -XPUT http://localhost:9200/index/type/1 -d ' 
{ 
    "field_a": "foo", 
    "field_b": "bar", 
    "field_x" : [{ 
     "user" : "1", 
     "field_x" : "A" 
    }, 
    { 
     "user" : "2", 
     "field_x" : "B" 
    }] 
}' 

并运行查询:

curl -XGET localhost:9200/index/type/_search -d '{ 
    "query": { 
     "nested" : { 
      "path" : "field_x", 
      "score_mode" : "avg", 
      "query" : { 
       "bool" : { 
        "must" : [ 
         { 
          "term": { 
           "field_x.user": "1" 
          } 
         }, 
         { 
          "term": { 
           "field_x.field_x": "A" 
          } 
         } 
        ] 
       } 
      } 
     } 
    } 
}'; 

这将导致

{"took":13,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":1.987628,"hits":[{"_index":"index","_type":"type","_id":"1","_score":1.987628, "_source" : 
{ 
    "field_a": "foo", 
    "field_b": "bar", 
    "field_x" : [{ 
     "user" : "1", 
     "field_x" : "A" 
    }, 
    { 
     "user" : "2", 
     "field_x" : "B" 
    }] 
}}]}} 

然而,查询

curl -XGET localhost:9200/index/type/_search -d '{ 
    "query": { 
     "nested" : { 
      "path" : "field_x", 
      "score_mode" : "avg", 
      "query" : { 
       "bool" : { 
        "must" : [ 
         { 
          "term": { 
           "field_x.user": "1" 
          } 
         }, 
         { 
          "term": { 
           "field_x.field_x": "B" 
          } 
         } 
        ] 
       } 
      } 
     } 
    } 
}'; 

将不会返回任何结果

{"took":6,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}} 
+0

这是一个伟大的答案。正是我在找什么。感谢您的彻底。 – Brad

+0

这是一个旧的答案,[见文档](https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-put-mapping。html)的更新版本,以了解映射URL如何变为“http:// localhost:9200/index/_mapping/type”。 –