我将从与 dt_matrix_token 表的第二个实例连接的 dt_matrix_token 表中的查询开始,其中两个实例都有一个 token_id在您感兴趣的值范围内,但它们不能具有相同的值。
它们还应该有一个匹配的storage_data_id(即它们在同一个文档中),并且第二个标记的位置必须大于或等于第一个。
SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
mt1.token_id AS token_id1, mt2.token_id AS token_id2,
mt1.position AS position1, mt2.position AS position2
FROM dt_matrix_token AS mt1
JOIN dt_matrix_token AS mt2
WHERE mt1.token_id IN (1,2,3)
AND mt2.token_id IN (1,2,3)
AND mt1.token_id <> mt2.token_id
AND mt1.storage_data_id = mt2.storage_data_id
AND mt2.position >= mt1.position
这为您提供了您关心的每一对连续的令牌。
现在,如果您按第一个表中的 dt_matrix_token_id 分组,并结合第二个表中的 token_id,您可以将该组结果缩小到每个 token_id 来自第二个表中的每个令牌。
当对第二张表的结果进行分组时,它是您关心的最小位置。由于第二个记号总是跟在第一个记号后面,因此您可以找到最接近第一个记号的位置。
SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
mt1.token_id AS token_id1, mt2.token_id AS token_id2,
mt1.position AS position1, MIN(mt2.position) AS position2
FROM dt_matrix_token AS mt1
JOIN dt_matrix_token AS mt2
WHERE mt1.token_id IN (1,2,3)
AND mt2.token_id IN (1,2,3)
AND mt2.token_id <> mt1.token_id
AND mt2.storage_data_id = mt1.storage_data_id
AND mt2.position >= mt1.position
GROUP BY mt1.dt_matrix_token_id, mt2.token_id
因此,现在,对于您关心的每个令牌实例,您都拥有与同一文档中跟随它的任何令牌最近的位置。
但你真正想要的是从第一个标记到它后面的任何标记的最大距离。所以你需要再次按dt_matrix_token_id分组,并计算到第二个位置最大值的距离(即每个token_id的最小值的最大值)。
SELECT dt_matrix_token_id, storage_data_id,
MAX(position2)-position1 AS distance
FROM (
SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
mt1.position AS position1, MIN(mt2.position) AS position2
FROM dt_matrix_token AS mt1
JOIN dt_matrix_token AS mt2
WHERE mt1.token_id IN (1,2,3)
AND mt2.token_id IN (1,2,3)
AND mt2.token_id <> mt1.token_id
AND mt2.storage_data_id = mt1.storage_data_id
AND mt2.position >= mt1.position
GROUP BY mt1.dt_matrix_token_id, mt2.token_id
) AS temp
GROUP BY dt_matrix_token_id
但是,并非第一个表中的每个标记都将跟随您关心的所有其他标记。所以你需要确保每组结果的COUNT等于你关心的token数减一(第一个表中有1个token,第二个表中有n-1个token)。
您可以使用 HAVING 子句 - HAVING COUNT(*) = 3-1 执行此操作,其中该表达式中的 3 表示您正在搜索的令牌数。
现在,对于您关心的令牌的每个实例,然后是您关心的所有其他令牌(在同一个文档中),您拥有覆盖所有令牌的最短距离。
但是每个文档很可能会有多个结果,您真的只需要知道每种情况下最短的一个。所以现在您需要按 storage_data_id 进行分组并计算组中的最小距离。
SELECT storage_data_id, MIN(distance) AS distance
FROM (
SELECT dt_matrix_token_id, storage_data_id,
MAX(position2)-position1 AS distance
FROM (
SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
mt1.position AS position1, MIN(mt2.position) AS position2
FROM dt_matrix_token AS mt1
JOIN dt_matrix_token AS mt2
WHERE mt1.token_id IN (1,2,3)
AND mt2.token_id IN (1,2,3)
AND mt2.token_id <> mt1.token_id
AND mt2.storage_data_id = mt1.storage_data_id
AND mt2.position >= mt1.position
GROUP BY mt1.dt_matrix_token_id, mt2.token_id
) AS temp
GROUP BY dt_matrix_token_id
HAVING COUNT(*) = 3-1
) AS temp
GROUP BY storage_data_id
这将为您提供包含您关心的所有标记的每个文档,以及覆盖所有这些标记的最小距离。要将结果限制在特定范围内的距离,您只需添加另一个 HAVING 子句即可。
HAVING distance <= 20
那么该查询的结果数应该告诉您有多少文档包含指定范围内您关心的所有标记。