在elasticsearch中存储聊天消息的最佳方式

时间:2016-09-14 10:57:54

标签: elasticsearch chat store messaging instant

我们目前正在我们的平台上实施即时消息系统。我们需要为用户提供聊天记录,并能够显示用户拥有的最后5个对话(在Facebook上预览)。

事实上,我们必须考虑如何存储所有这些数据

我们正在使用 Elasticsearch ,我们认为这可以成为存储聊天消息并使其高度可用于读取操作的可靠解决方案。

我们的问题是,什么是 Elasticsearch中最好的数据结构,以便我们的读取操作可以快速而不是太重。

我们想到了很多解决方案,这可能是我们提出的最佳解决方案。

我们的消息表示可能是:

{ 
   "ID" : 1,
   "sender" : "john",
   "receiver" : "doe",
   "content" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
   "date" : "timestamp"
}

我们可以使用嵌套对象在对话中存储消息:

 {
     "ID" : 317,
     "participants" : "john, doe",
     "date" : "timestamp of the last received message",
     "messages": [
         {
            "ID": "49753",
            "sender" : "john", 
            "receiver" : "doe",
            "content" : " Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            "date" : "timestamp" 
         },
         {
            "ID": "49754",
            "sender" : "doe", 
            "receiver" :"john",
            "content" : " Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            "date" : "timestamp" 
         },....
               ]
}

我们希望得到您对此解决方案的反馈意见,如果您有更好的解决方案,我们也会提供您的解决方案。

提前致谢

1 个答案:

答案 0 :(得分:11)

注意:这个建议的解决方案不仅从快速读取的角度(如OP的要求),而且还着眼于最小化索引开销。嵌套文档及其父项被写为单个块,因此添加了每个附加的"消息"在嵌套提案中,会导致该对话中的所有先前消息和对话数据也被重新编制索引。

以下是我对Facebook实施消息的一般方法的猜测(如果您使用Elasticsearch做类似的事情)

enter image description here

预览 :(在Messages导航栏下拉列表中,以及消息页面的左栏)

使用以下方式显示最近对话的摘要:

  • 最近三位对话参与者的订购列表中最近三位参与者的综合爆头。
  • 如果>其他参与者的数量3
  • 对话中最近一条消息的时间戳
  • 对话中最新消息的摘录

消息窗格 :( 消息的中心列页面)

  • 显示对话中的所有消息
  • 消息窗格也重新用于消息搜索结果,显示包含搜索词的所有消息。

搜索框

  • 预先输入:(使用匹配的参与者姓名完成对话
  • 搜索:(使用邮件正文中的匹配文字在上搜索邮件

驱动预览的数据结构可能位于conversation索引中(每个对话包含一个文档)。每次将消息添加到对话时,都会更新这些文档。 (非常类似于嵌套示例文档的父记录)。

conversation数据源仅用于绘制预览(对话参与者的快速过滤,以确保您只能看到您所参与的对话)。

 {
     "ID" : 317,
     "participant_ids": [123456789, 987654321],
     "participant_names: ["John Doe", "Jane Doe"],
     "last_message_snippet" : " Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
     "last_message_timestamp" : "timestamp of the last received message",
 }

这里没有嵌套b / c只需要最新的会话摘要,而不是消息。

效果会很快,因为不需要评分,只需participant_ids中[当前用户]的过滤器和last_message_timestamp的降序排序。

您可以使用participant_names字段上的Elasticsearch Term Suggester复制预先输入功能。

较少数量的conversation文档(vs message文档)将有助于索引更新此频繁的功能。

为了进一步扩展此功能,可以使用Index Per Timeframe索引策略(例如,时间范围由对话的典型半衰期决定)。

在特定conversation内显示 消息时,您将查询带有您的消息文档示例的message索引,但是引用了conversation

 {
     "ID" : 4828274,
     "conversation_id": 317,
     "conversation_participant_ids": [123456789, 987654321],
     "sender_id": 123456789,
     "sender_name: "John Doe",
     "message" : " Lorem ipsum dolor sit amet, consectetur adipiscing elit",
     "message_timestamp" : <timestamp>,
 }

效果会很快,因为不需要评分,只需conversation_id上的过滤器和message_timestamp的降序排序。

在对话中搜索 消息时,您只需要对message字段编制索引。 (遵循Facebook实施)。

搜索查询将是conversation_participant_ids中[当前用户]过滤的搜索字词,按message_timestamp降序排序。

要在检索对话的消息时最大限度地减少搜索群集中的串扰,您需要确保利用Elasticsearch's routing parameter (on indexing requests)明确共同定位所有对话的消息。相同的分片,在为新邮件编制索引时使用conversation_id作为routing值。

注意:Elasticsearch可能会变得过度,无法实现一个主要由其他文档存储或具有文本搜索功能的关系数据库构建的解决方案。通过在上面的示例中对conversationmessage进行规范化,不再依赖于&#34;嵌套&#34;在Elasticsearch中。

此实现的Elasticsearch 优势包括过滤搜索结果的高效缓存,快速自动完成和快速文本搜索,但Elasticsearch的弱点需要足够的内存来舒适地容纳所有索引数据。

Messaging应用程序的性能特征决定了只能使用任何频率访问或搜索最新消息,所以在某些时候,如果您的应用程序需要扩展,您应该计划在&#34;冷藏&#34;中存档旧的,不是最近访问过的消息的方法。这样他们需要更少的应用程序资源,但仍然可以“解冻”#34;足够快,可以在没有过多延迟的情况下提供关键字搜索。