【发布时间】:2021-03-03 09:45:44
【问题描述】:
我已经构建了一个系统,用于跨不同平台(例如 MSN Messenger、Hangouts、WhatsApp)归档、汇总和索引我的 IM 历史记录。数据当前存储在 SQLite3 数据库中,架构的相关部分如下所示:
CREATE TABLE messages (
message_id TEXT PRIMARY KEY,
conversation_id TEXT,
sender_id TEXT,
sent_micros BIGINT, -- microseconds since epoch
received_micros BIGINT,
read_micros BIGINT,
message_plain TEXT,
-- various other columns
)
所有列上还有NOT NULL 约束,但我跳过了这些约束以使架构更易于阅读。
我想做的是实现“使用上下文搜索”,其中显示结果周围(之前/之后)的记录。这是一个示例,添加了假语法和换行符,以便更容易区分结果组:
RETURNING CONTEXT 3 ROWS AROUND PARTITION BY conversation_id ORDER BY sent_micros ASC
SELECT message_id, conversation_id, sender_id, sent_micros, message_plain FROM messages
WHERE message_plain LIKE '%Waterdeep%'
ORDER BY sent_micros ASC, conversation_id ASC;
message_id | conversation_id | sender_id | sent_s | message_plain
-----------+-----------------+------------+-------------+-----------------------------------------
xkezwE9bMz | Mv3YdQsXZw | vBPkl8G8e4 | 1614762003… | what did you want to play later?
PKhydJ3TCM | Mv3YdQsXZw | i3QsU2T2ms | 1614762008… | I dunno
umfTYF2Qlv | Mv3YdQsXZw | i3QsU2T2ms | 1614762009… | well actually
RJy6MVAQYv | Mv3YdQsXZw | i3QsU2T2ms | 1614762011… | what about Lords of Waterdeep?
k2V49Ls1Jj | Mv3YdQsXZw | vBPkl8G8e4 | 1614762314… | sounds good
PpUSRDVC9O | Mv3YdQsXZw | vBPkl8G8e4 | 1614762315… | maybe I'll even let you win this time!
HNaiAd0zY6 | Mv3YdQsXZw | i3QsU2T2ms | 1614762322… | hah, like that would ever happen
TUR5ZvEBMB | P2nclp3jaG | vBPkl8G8e4 | 1614726660… | I'm heading to bed
au72U5GaQQ | P2nclp3jaG | vBPkl8G8e4 | 1614726661… | goodnight
HFGXbn1X0S | P2nclp3jaG | KcDHZ9zM4c | 1614727012… | 'night
E6u30kU7Fo | P2nclp3jaG | vBPkl8G8e4 | 1614762840… | did Sam get the Waterdeep expansion?
ssTPVZO1ce | P2nclp3jaG | KcDHZ9zM4c | 1614762921… | yeah
WEA69uNJ7a | P2nclp3jaG | KcDHZ9zM4c | 1614762926… | we're hoping to play it soon
wktsSF3L3l | P2nclp3jaG | KcDHZ9zM4c | 1614762934… | like maybe this weekend
请注意,时间戳仅在一组记录中排序; “我要睡觉了”在“你以后想玩什么?”之前发送。但“深水”行的顺序正确。
我能想到的唯一方法是使用 2n + 1 个查询:
SELECT message_id, conversation_id, sent_micros FROM messages WHERE message_plain LIKE '%Waterdeep%' ORDER BY sent_micros ASC- 对于该结果中的每一行:
SELECT * FROM messages WHERE conversation_id = :conversation_id AND sent_micros >= :sent_micros ORDER BY sent_micros ASC LIMIT 4SELECT * FROM messages WHERE conversation_id = :conversation_id AND sent_micros <= :sent_micros ORDER BY sent_micros DESC LIMIT 4
但这似乎非常浪费和低效。
有没有更好的方法来处理这个问题?窗口函数有用吗?不同的数据库引擎会有帮助吗?
似乎在某个时候我会添加全文搜索功能,而不是简单的基于LIKE 的匹配。我想这基本上只会给出查询的message_id结果,所以感觉就像是某种“返回n行围绕主键值x, y, z" 解决方案将是理想的。基于LIKE 的查询可以分解为该形式,并且只会是两个查询而不是2n + 1。
【问题讨论】:
标签: sql sqlite window-functions