SQLite FTS4使用首选语言

时间:2015-03-17 12:38:50

标签: sqlite full-text-search materialize

我有一个使用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执行了两次查找(这可能是个错误吗?)。

提前致谢:)

2 个答案:

答案 0 :(得分:4)

您可以使用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),并通过加入rowid的{​​{1}}来过滤行。 这样您只需要查询一次FTS表 - 使用临时表存储FTS表结果,然后使用元表对它们进行排序。

答案 1 :(得分: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>