【问题标题】:SQLite FTS4 with preferred language首选语言的 SQLite FTS4
【发布时间】:2015-05-19 21:27:28
【问题描述】:

我有一个使用 FTS4 模块生成的 SQLite 表。每个条目至少用不同的语言列出两次,但仍共享一个唯一 ID(int 列,未编入索引)。 这是我想做的事情: 我想查找首选语言的术语。我想将结果与使用另一种语言的相同术语的查找结合起来。 不过,对于第二次查找,我想忽略在第一次查找期间已经找到的所有条目(由其 ID 标识)。所以基本上我想这样做:

WITH term_search1 AS (
    SELECT *
    FROM myFts
    WHERE myFts MATCH 'term'
    AND languageId = 1)
SELECT *
FROM term_search1
UNION
SELECT *
FROM myFts
WHERE myFts MATCH 'term'
AND languageId = 2
AND id NOT IN (SELECT id FROM term_search1)

这里的问题是 term_seach1 查询将被执行两次。有没有办法实现我的结果?任何将其限制为 2 个查询(而不是 3 个)的解决方案都会很棒。

我也尝试过使用递归查询,例如:

WITH RECURSIVE term_search1 AS (
    SELECT *
    FROM myFts
    WHERE myFts MATCH 'term'
    AND languageId = 1
UNION ALL
    SELECT m.*
    FROM myFts m LEFT OUTER JOIN term_search1 t ON (m.id = t.id)
    WHERE myFts MATCH 'term'
    AND m.languageId = 2
    AND t.id IS NULL
)
SELECT * FROM term_search1

这也没有用。显然他刚刚对 languageId = 2 执行了两次查找(这可能是一个错误吗?)。

提前致谢:)

【问题讨论】:

    标签: sqlite full-text-search materialize


    【解决方案1】:

    您可以使用 TEMPORARY 表将 myFts 的查询次数减少到 2:

    CREATE TEMP TABLE results (id INTEGER PRIMARY KEY);
    
    INSERT INTO results 
        SELECT id FROM myFts
        WHERE myFts MATCH 'term' AND languageId = 1;
    
    INSERT INTO results
        SELECT id FROM myFts
        WHERE myFts MATCH 'term' AND languageId = 2
        AND id NOT IN (SELECT id FROM results);
    
    SELECT * FROM myFts
        WHERE id IN (SELECT id FROM results);
    
    DROP TABLE results;
    

    如果可以更改架构,您应该只将文本数据保留在 FTS 表中。这样,当您搜索与 languageId 不匹配的数字和行时,您将避免不正确的结果。创建另一个包含非文本数据的元表(如idlanguageId)并通过加入myFtsrowid 来过滤行。 这样您只需查询 FTS 表一次 - 使用临时表存储 FTS 表结果,然后使用元表对其进行排序。

    【讨论】:

    • 嗨,到目前为止,创建临时表显然是唯一能以某种方式解决问题的解决方案(经常执行时听起来仍然像性能杀手)。关于架构相关的东西.. languageId 实际上不是我的“自己的”专栏。它是 FTS 功能的一部分(隐藏列)。根据 FTS 文档“单个 FTS 查询不可能返回具有不同语言 ID 值的行”:/ 这就是为什么我总是需要至少 2 个查询。
    • 创建一个临时表绝对是一种开销,但它可能仍然是高性能的。不幸的是,我的 SQLite 无法创建带有语言 ID 扩展名的 FTS4,因此我无法分析查询。您需要不同的标记器而不使用默认的 unicode61 的任何特殊原因?
    【解决方案2】:

    这是我能想到的最好的:

    SELECT *
    FROM myFts t1
    JOIN (SELECT COUNT(*) AS cnt, id 
          FROM myFts t2
          WHERE t2.languageId in (1, 2) 
          AND t2.myFts MATCH 'term'
          GROUP BY t2.id) t3
    ON t1.id = t3.id
    WHERE t1.myFts MATCH 'term'
        AND t1.languageId in (1, 2) 
        AND (t1.languageId = 1 or t3.cnt = 1)
    

    我不确定第二个MATCH 子句是否必要。 这个想法是首先计算可接受的行,然后选择最好的行。

    编辑:我不知道为什么它不适用于您的表格。这是我为测试它所做的(SQLite 版本 3.8.10.2):

    CREATE VIRTUAL TABLE myFts USING fts4(
      id integer,
      languageId integer,
      content TEXT
    );
    
    insert into myFts(id, languageId, content) values (10, 1, 'term 10 lang 1');
    insert into myFts(id, languageId, content) values (10, 2, 'term 10 lang 2');
    insert into myFts(id, languageId, content) values (11, 1, 'term 11 lang 1');
    insert into myFts(id, languageId, content) values (12, 2, 'term 12 lang 2');
    insert into myFts(id, languageId, content) values (13, 1, 'not_erm 13 lang 1');
    insert into myFts(id, languageId, content) values (13, 2, 'term 13 lang 2');
    

    执行查询给出:

    sqlite> SELECT *
       ...> FROM myFts t1
       ...> JOIN (SELECT COUNT(*) AS cnt, id 
       ...>       FROM myFts t2
       ...>       WHERE t2.languageId in (1, 2) 
       ...>       AND t2.myFts MATCH 'term'
       ...>       GROUP BY t2.id) t3
       ...> ON t1.id = t3.id
       ...> WHERE t1.myFts MATCH 'term'
       ...>     AND t1.languageId in (1, 2) 
       ...>     AND (t1.languageId = 1 or t3.cnt = 1);
    10|1|term 10 lang 1|2|10
    11|1|term 11 lang 1|1|11
    12|2|term 12 lang 2|1|12
    13|2|term 13 lang 2|1|13
    sqlite> 
    

    【讨论】:

    • 您好,很遗憾您的查询不起作用。根据 SQLite 文档“单个 FTS 查询不可能返回具有不同语言 ID 值的行”:/ 这就是为什么我必须首先将其拆分为 2 个查询。
    • 奇怪,我测试了它,它似乎工作。你的表是如何定义的?
    • 您没有使用 languageId 功能。尝试使用CREATE VIRTUAL TABLE myFts USING fts4( id, content, languageid="languageId"); 创建表然后即使像select * from myFts where content match "term*"; 这样的简单查询也不会返回结果,因为它假定languageId = 0
    • 我不知道 FTS4 languageId= 选项。它限制了查询中可以做的事情,我必须研究一下
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    相关资源
    最近更新 更多