Точная фраза, прежде чем что-либо еще в 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*' 

Что я делаю здесь:

  1. Во внутреннем SELECT я делаю сортировку
  2. В следующем SELECT я отфильтрую дубликаты (это будет работать, потому что я пока не использую сниппет).
  3. Наконец, я выбираю фрагмент, если 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"');
Другие вопросы по тегам