共享索引 (Shared Index)edit

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

PUT /forums
{
  "settings": {
    "number_of_shards": 10 
  },
  "mappings": {
    "post": {
      "properties": {
        "forum_id": { 
          "type":  "string",
          "index": "not_analyzed"
        }
      }
    }
  }
}

PUT /forums/post/1
{
  "forum_id": "baking", 
  "title":    "Easy recipe for ginger nuts",
  ...
}

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

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

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

GET /forums/post/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "title": "ginger nuts"
        }
      },
      "filter": {
        "term": {
          "forum_id": {
            "baking"
          }
        }
      }
    }
  }
}

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

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

shard = hash(routing) % number_of_primary_shards

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

PUT /forums/post/1?routing=baking 
{
  "forum_id": "baking", 
  "title":    "Easy recipe for ginger nuts",
  ...
}

forum_id 用于路由值,确保来自同一个论坛的所有帖子都存储于相同的分片。

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

GET /forums/post/_search?routing=baking 
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "title": "ginger nuts"
        }
      },
      "filter": {
        "term": { 
          "forum_id": {
            "baking"
          }
        }
      }
    }
  }
}

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

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

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

GET /forums/post/_search?routing=baking,cooking,recipes
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "title": "ginger nuts"
        }
      },
      "filter": {
        "terms": {
          "forum_id": {
            [ "baking", "cooking", "recipes" ]
          }
        }
      }
    }
  }
}

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