2013-07-08 159 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」。 –