Точная фраза, прежде чем что-либо еще в SQLite FTS?
Предположим, что поисковый ввод "что есть". Это будет соответствовать "что бы это ни было", а также "что есть", что является точной фразой. Теперь, как мне сделать точную фразу первой в сортировке?
Я думал об этом со вчерашнего дня и продолжаю придумывать разные решения, но у каждого есть свой недостаток.
Вот мой неудачный подход (предположим, что input = 'what is'):
SELECT snippet(fts), 1 as rank
FROM fts
WHERE body MATCH '"what is"'
UNION ALL
SELECT snippet(fts), 2 as rank
FROM fts
WHERE body MATCH 'what* NEAR/3 is*' -- 3 is arbitrary
ORDER BY rank
- Проблема в этом состоит в том, что два SELECT не являются взаимоисключающими, поэтому будут дубликаты.
- Я не могу использовать UNION, так как они различаются по столбцу ранга и функции фрагмента (сначала будет START| что такое |END, у других будет START| что |ENDSTART| это |END).
- Я также не могу использовать это (мой предыдущий вопрос), поскольку MATCH не будет работать в предложении ORDER BY (потому что результирующая таблица /select не является исходной таблицей FTS).
Вот мое текущее решение:
SELECT snippet(fts)
FROM fts WHERE rowId IN
(
SELECT DISTINCT rowId
FROM
(
SELECT rowId, 1 as rank
FROM fts
WHERE body MATCH '"what is"'
UNION ALL
SELECT rowId, 2 as rank
FROM fts
WHERE body MATCH 'what* NEAR/3 is*'
ORDER BY rank
)
)
WHERE body MATCH 'what* NEAR/3 is*'
Что я делаю здесь:
- Во внутреннем SELECT я делаю сортировку
- В следующем SELECT я отфильтрую дубликаты (это будет работать, потому что я пока не использую сниппет).
- Наконец, я выбираю фрагмент, если rowId находится во втором выборе.
Проблема здесь в том, что, как вы ожидаете, заказ полностью исчез:(.
РЕДАКТИРОВАТЬ:
Я использую FTS4 в Android (я не использую расширенный синтаксис запросов, потому что я не уверен, что Android поддерживает это).
1 ответ
Вы должны сделать всю обработку FTS (включая snippet()
) в самой таблице FTS и только потом объедините результат в самом верхнем запросе:
SELECT docid,
snippet,
MIN(rank) AS rank
FROM (SELECT docid,
snippet(fts) AS snippet,
1 AS rank
FROM fts
WHERE body MATCH '"what is"'
UNION ALL
SELECT docid,
snippet(fts),
2
FROM fts
WHERE body MATCH 'what* NEAR/3 is*')
GROUP BY docid
ORDER BY MIN(rank) /*, docid*/;
В качестве альтернативы, получите все возможные строки с более общим шаблоном и проверьте для более строгого соответствия в ORDER BY:
SELECT snippet(fts)
FROM fts
WHERE body MATCH 'what* NEAR/3 is*'
ORDER BY NOT (body MATCH '"what is"');