学习 Elasticsearch 的第12天

216 阅读3分钟

这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

应用层联接

我们通过在我们的应用程序中实现联接可以(部分)模拟关系数据库。 例如,比方说我们正在对用户和他们的博客文章进行索引。在关系世界中,我们会这样来操作:

PUT /my_index/user/1 
{
  "name":     "John Smith",
  "email":    "john@smith.com",
  "dob":      "1970/10/24"
}

PUT /my_index/blogpost/2 
{
  "title":    "Relationships",
  "body":     "It's complicated...",
  "user":     1 
}
**每个文档的 indextype, 和 id 一起构造成主键。
**blogpost 通过用户的 id 链接到用户。index 和 type 并不需要因为在我们的应用程序中已经硬编码。

通过用户的 ID 1 可以很容易的找到博客帖子。

GET /my_index/blogpost/_search
{
  "query": {
    "filtered": {
      "filter": {
        "term": { "user": 1 }
      }
    }
  }
}

为了找到用户叫做 John 的博客帖子,我们需要运行两次查询: 第一次会查找所有叫做 John 的用户从而获取他们的 ID 集合,接着第二次会将这些 ID 集合放到类似于前面一个例子的查询:

GET /my_index/user/_search
{
  "query": {
    "match": {
      "name": "John"
    }
  }
}

GET /my_index/blogpost/_search
{
  "query": {
    "filtered": {
      "filter": {
        "terms": { "user": [1] }  
      }
    }
  }
}
**执行第一个查询得到的结果将填充到 terms 过滤器中。

应用层联接的主要优点是可以对数据进行标准化处理。只能在 user 文档中修改用户的名称。缺点是,为了在搜索时联接文档,必须运行额外的查询。

在这个例子中,只有一个用户匹配我们的第一个查询,但在现实世界中,我们可以很轻易的遇到数以百万计的叫做 John 的用户。 包含所有这些用户的 IDs 会产生一个非常大的查询,这是一个数百万词项的查找。

这种方法适用于第一个实体(例如,在这个例子中 user )只有少量的文档记录的情况,并且最好它们很少改变。这将允许应用程序对结果进行缓存,并避免经常运行第一次查询。

非规范化的数据

使用 Elasticsearch 得到最好的搜索性能的方法是有目的的通过在索引时进行非规范化 denormalizing。对每个文档保持一定数量的冗余副本可以在需要访问时避免进行关联。

如果我们希望能够通过某个用户姓名找到他写的博客文章,可以在博客文档中包含这个用户的姓名:

PUT /my_index/user/1
{
  "name":     "John Smith",
  "email":    "john@smith.com",
  "dob":      "1970/10/24"
}

PUT /my_index/blogpost/2
{
  "title":    "Relationships",
  "body":     "It's complicated...",
  "user":     {
    "id":       1,
    "name":     "John Smith" 
  }
}
**这部分用户的字段数据已被冗余到 blogpost 文档中。

现在,我们通过单次查询就能够通过 relationships 找到用户 John 的博客文章。

GET /my_index/blogpost/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title":     "relationships" }},
        { "match": { "user.name": "John"          }}
      ]
    }
  }
}

数据非规范化的优点是速度快。因为每个文档都包含了所需的所有信息,当这些信息需要在查询进行匹配时,并不需要进行昂贵的联接操作。

\