共享索引

我们可以为许多的小论坛使用一个大的共享的索引,将论坛标识索引进一个字段并且将它用作一个过滤器:

  1. PUT /forums
  2. {
  3. "settings": {
  4. "number_of_shards": 10 (1)
  5. },
  6. "mappings": {
  7. "post": {
  8. "properties": {
  9. "forum_id": { (2)
  10. "type": "string",
  11. "index": "not_analyzed"
  12. }
  13. }
  14. }
  15. }
  16. }
  17. PUT /forums/post/1
  18. {
  19. "forum_id": "baking", (2)
  20. "title": "Easy recipe for ginger nuts",
  21. ...
  22. }

<1> 创建一个足够大的索引来存储数千个小论坛的数据。

<2> 每个帖子都必须包含一个 forum_id 来标识它属于哪个论坛。

我们可以把 forum_id 用作一个过滤器来针对单个论坛进行搜索。这个过滤器可以排除索引中绝大部分的数据(属于其它论坛的数据),缓存会保证快速的响应:

  1. GET /forums/post/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": {
  6. "match": {
  7. "title": "ginger nuts"
  8. }
  9. },
  10. "filter": {
  11. "term": {
  12. "forum_id": {
  13. "baking"
  14. }
  15. }
  16. }
  17. }
  18. }
  19. }

这个办法行得通,但我们可以做得更好。来自于同一个论坛的帖子可以简单地容纳于单个分片,但它们现在被打散到了这个索引的所有十个分片中。这意味着每个搜索请求都必须被转发至所有十个分片的一个主分片或者副本分片。如果能够保证所有来自于同一个论坛的所有帖子都被存储于同一个分片可能会是个好想法。

routing-value,我们说过一个文档将通过使用如下公式来分配到一个指定分片:

  1. shard = hash(routing) % number_of_primary_shards

routing 的值默认为文档的 _id ,但我们可以覆盖它并且提供我们自己自定义的路由值,例如 forum_id 。 所有有着相同 routing 值的文档都将被存储于相同的分片:

  1. PUT /forums/post/1?routing=baking (1)
  2. {
  3. "forum_id": "baking", (1)
  4. "title": "Easy recipe for ginger nuts",
  5. ...
  6. }

<1> 将 forum_id 用于路由值保证所有来自相同论坛的帖子都存储于相同的分片。

当我们搜索一个指定论坛的帖子时,我们可以传递相同的 routing 值来保证搜索请求仅在存有我们文档的分片上执行:

  1. GET /forums/post/_search?routing=baking (1)
  2. {
  3. "query": {
  4. "bool": {
  5. "must": {
  6. "match": {
  7. "title": "ginger nuts"
  8. }
  9. },
  10. "filter": {
  11. "term": { (2)
  12. "forum_id": {
  13. "baking"
  14. }
  15. }
  16. }
  17. }
  18. }
  19. }

<1> 查询请求仅在对应于 routing 值的分片上执行。

<2> 我们还是需要过滤(Filter)查询,因为一个分片可以存储来自于很多论坛的帖子。

多个论坛可以通过传递一个逗号分隔的列表来指定 routing 值,然后将每个 forum_id 包含于一个 terms 查询:

  1. GET /forums/post/_search?routing=baking,cooking,recipes
  2. {
  3. "query": {
  4. "bool": {
  5. "must": {
  6. "match": {
  7. "title": "ginger nuts"
  8. }
  9. },
  10. "filter": {
  11. "terms": {
  12. "forum_id": {
  13. [ "baking", "cooking", "recipes" ]
  14. }
  15. }
  16. }
  17. }
  18. }
  19. }

这种方式从技术上来说比较高效,由于要为每一个查询或者索引请求指定 routingterms 的值看起来有一点的笨拙。 索引别名可以帮你解决这些!