基于Lindorm宽表及搜索引擎的IM场景案例

更新时间:
复制 MD 格式

本文以即时通讯(IM)应用为例,详细介绍了如何使用 Lindorm 宽表引擎作为核心存储。内容覆盖了从实例的开通与连接、数据表的设计与操作,到如何利用二级索引和搜索索引分别加速精确查询和全文检索的全过程,为您构建高性能消息系统提供清晰的实践指导。

方案概述

本方案将利用 Lindorm 宽表引擎作为核心存储,并通过以下两种索引能力,满足 IM 场景下多样化的查询需求:

  1. 原生二级索引:用于加速基于非主键列的高频、确定性查询,如“查询某用户的最近消息”、“查询某群组的最新消息”等场景。

  2. 搜索索引:基于搜索引擎实现,用于支持复杂的多维查询和全文检索,如“搜索包含特定关键词的消息”、“按多个条件组合过滤”等场景。

前提条件

  • 已完成Lindorm宽表引擎实例的创建。

  • 实例已开通Lindorm搜索引擎和LTS引擎。开通方法请参见开通指南

  • 已将客户端IP添加至Lindorm白名单。添加方法请参见设置白名单

创建消息表

表结构设计

我们设计一个名为 im_messages 的表来存储消息数据。

字段

类型

说明

msg_id

VARCHAR

主键。消息的唯一 ID,全局唯一以避免写入热点。

from_user

VARCHAR

发送者 ID。

to_user

VARCHAR

接收者 ID(私聊时使用)。

group_id

VARCHAR

群组 ID(群聊时使用)。

content

VARCHAR

消息内容(建议使用 VARCHAR 以便于后续创建搜索索引)。

msg_type

VARCHAR

消息类型(如 text, image, file)。

send_time

BIGINT

发送时间戳(毫秒)。

status

VARCHAR

消息状态(如 sent, delivered, read)。

is_deleted

BOOLEAN

逻辑删除标记,用于实现消息撤回等功能。

建表语句

执行以下 SQL 语句创建 im_messages 表:

CREATE TABLE IF NOT EXISTS im_messages (
    msg_id VARCHAR,
    from_user VARCHAR,
    to_user VARCHAR,
    group_id VARCHAR,
    content VARCHAR,
    msg_type VARCHAR,
    send_time BIGINT,
    status VARCHAR,
    is_deleted BOOLEAN,  -- 建议添加逻辑删除标记,便于消息撤回
    PRIMARY KEY(msg_id)
);

写入与查询数据

写入测试数据

使用 UPSERT 语句插入或更新数据。以下是 5 条示例消息:

-- 插入 5 条测试消息
UPSERT INTO im_messages (
    msg_id,
    from_user,
    to_user,
    group_id,
    content,
    msg_type,
    send_time,
    status
) VALUES
('m001', 'u1001', 'u1002', NULL, 'Hello!', 'text', 1704000000000, 'read'),
('m002', 'u1002', 'u1001', NULL, 'Hi there', 'text', 1704000060000, 'read'),
('m003', 'u1001', NULL, 'g2001', '大家好', 'text', 1704000120000, 'sent'),
('m004', 'u1003', NULL, 'g2001', '收到', 'text', 1704000180000, 'delivered'),
('m005', 'u1001', 'u1004', NULL, '图片.jpg', 'image', 1704000240000, 'sent');

数据查询

  • 主键查询(最高效)

    根据消息 ID 精确查询消息内容,这是 Lindorm 最高效的点查方式。

    SELECT content 
    FROM im_messages 
    WHERE msg_id = 'm001';
  • 简单聚合分析

    注意:在没有索引的情况下,以下聚合查询会触发全表扫描。在小数据量下可用于逻辑验证,但在生产环境中应依赖搜索索引或列存来高效执行。
    • 统计全表消息总数

      SELECT COUNT(*) FROM im_messages;
    • 按消息类型分布统计

      SELECT msg_type, COUNT(*) FROM im_messages GROUP BY msg_type;
    • 检查某用户是否有未读消息

      SELECT COUNT(*) FROM im_messages WHERE to_user = 'u1002' AND status = 'sent';

使用二级索引加速查询

为了支持常见的非主键查询(如“查某用户的消息”、“查群消息”等),我们需要为高频查询字段创建合适的二级索引。

索引设计

根据典型的 IM 查询场景,我们设计以下索引:

索引名称

索引字段

查询场景

idx_from_user_time

(from_user, send_time DESC)

查询某用户最近发送的 N 条消息

idx_group_id

(group_id)

查询某个群的所有消息

idx_send_time

(send_time)

按时间范围查询(需配合其他条件)

idx_to_user_time

(to_user, send_time DESC)

查询某用户收到的最近私聊消息

idx_group_time

(group_id, send_time DESC)

查询某群最近 N 条消息

创建索引语句

执行以下 SQL 创建二级索引。创建过程需要几秒到几分钟,具体时间取决于存量数据量。

-- 1. 【重点】发送者 + 时间(倒序)—— 用于“某用户最近消息”
CREATE INDEX IF NOT EXISTS idx_from_user_time ON im_messages (from_user, send_time DESC);

-- 2. 【重点】接收者 + 时间(倒序)—— 用于“某用户最新私聊”
CREATE INDEX IF NOT EXISTS idx_to_user_time ON im_messages (to_user, send_time DESC);

-- 3. 【重点】群组 + 时间(倒序)—— 用于“某群最新消息”
CREATE INDEX IF NOT EXISTS idx_group_time ON im_messages (group_id, send_time DESC);

-- 4. 时间索引(单独用较少,通常用于联合)
CREATE INDEX IF NOT EXISTS idx_send_time ON im_messages (send_time);

使用二级索引查询示例

  • 查询 u1001 最近 10 条发送的消息 (将命中 idx_from_user_time 索引)

    SELECT msg_id, content, send_time
    FROM im_messages
    WHERE from_user = 'u1001'
    ORDER BY send_time DESC
    LIMIT 10;
  • 查询 u1002 收到的最近 5 条私聊 (将命中 idx_to_user_time 索引)

    SELECT msg_id, from_user, content
    FROM im_messages
    WHERE to_user = 'u1002'
    ORDER BY send_time DESC
    LIMIT 5;
  • 查询群 g2001 的最新 20 条消息 (将命中 idx_group_time 索引)

    SELECT msg_id, from_user, content, send_time
    FROM im_messages
    WHERE group_id = 'g2001'
    ORDER BY send_time DESC
    LIMIT 20;
  • 查询某时间段内 u1001 发的消息(将命中 idx_send_time 索引)

    SELECT msg_id, content
    FROM im_messages
    WHERE from_user = 'u1001'
      AND send_time BETWEEN 1704000000000 AND 1704000300000
    ORDER BY send_time DESC;

使用搜索索引支持全文检索和复杂查询

对于全文检索和复杂的多条件组合查询,搜索索引是理想的解决方案。它提供了分词、模糊查询、聚合分析以及高效的排序和分页等高级功能,能够轻松满足从关键词搜索到报表分析等多样化的查询需求。

创建搜索索引

执行以下 SQL 创建一个名为 im_search_idx 的搜索索引。Lindorm 会通过 LTS 自动将宽表数据同步到搜索引擎。

-- 创建名为 im_search_idx 的搜索索引
CREATE INDEX im_search_idx 
USING SEARCH
ON im_messages (
    msg_id,          					-- 精确匹配(主键)
    from_user,      					-- 发送者(精确)
    to_user,         					-- 接收者(精确)
    group_id,        					-- 群ID(精确)
    content(type=text,analyzer=ik), 	-- 全文检索字段(启用分词)
    msg_type,        					-- 消息类型(精确)
    send_time,       					-- 时间戳(支持范围查询/排序)
    status           					-- 状态(精确)
);

您可以使用 SHOW INDEX FROM im_messages; 查看索引的创建状态。

使用搜索索引查询示例

  • 搜索包含“图片”的消息(全文检索)

    SELECT msg_id, from_user, content 
    FROM im_messages
    WHERE content LIKE '%图片%'
  • 查询 u1001 发送的且包含“Hello”的消息(多条件组合)

    SELECT msg_id, content, send_time
    FROM im_messages
    WHERE from_user = 'u1001' AND content LIKE '%Hello%'
  • 群 g2001 中最近的10条消息

    SELECT msg_id, content
    FROM im_messages
    WHERE group_id = 'g2001' 
      AND send_time IS NOT NULL
    ORDER BY send_time DESC
    LIMIT 10;