SQL Server взвешенный полнотекстовый поиск

Сегодня и snprintf, и vsnprintf должны быть доступны везде, кроме Windows с MSVC12 и старше. Самый простой способ для вас - предоставить snprintf / vsnprintf в Windows, где он недоступен.

Windows предоставляет функцию _vsnprintf_s, которая уже аналогична vsnprintf, но имеет следующие важные различия в отношении того, что происходит, когда буфер слишком мал:

  • Содержимое буфера зависит от count Аргумент, которого нет в vsnprintf. Чтобы получить vsnprintf поведение, вы можете передать _TRUNCATE здесь.
  • -1 возвращается вместо необходимого количества символов. Это можно исправить с помощью функции _vscprintf, которую нужно вызывать только в случае сбоя предыдущего вызова _vsnprintf_s.

Кроме того, эти функции не поддерживают спецификаторы формата, добавленные в C99, такие как %zd. Это не может быть легко решено, вам придется избегать их использования.

Код ниже:

int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
    int r = -1;

    if (size != 0)
    {
        va_list args_copy;
        va_copy(args_copy, args);
        r = _vsnprintf_s(buf, size, _TRUNCATE, fmt, args_copy);
        va_end(args_copy);
    }

    if (r == -1)
    {
        r = _vscprintf(fmt, args);
    }

    return r;
}

int snprintf(char *buf, size_t size, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    int r = vsnprintf(buf, size, fmt, args);
    va_end(args);
    return r;
}

Примечание: Windows также предоставляет _vsnprintf, который выглядит лучше подходящим для этой реализации, но не завершает результирующую строку. Если вы хотите использовать его, вы должны быть осторожны.

7
задан Community 23 May 2017 в 12:08
поделиться

3 ответа

Ключ к управлению рейтингами должен использовать объединение. Для каждого столбца Вы используете отдельный избранный оператор. В том операторе добавьте идентификатор, который показывает, от которого столбца каждую строку вытянули затем. Вставьте результаты в табличную переменную, затем можно управлять рейтингом путем сортировки на идентификаторе или умножения разряда на некоторое значение на основе идентификатора.

Ключ должен дать появление изменения рейтинга, для не фактического изменения рейтинга SQL-сервера.

Пример с помощью табличной переменной:

DECLARE @Results TABLE (PersonId Int, Rank Int, Source Int)

Для таблицы People with Columns PersonId Int PK Identity, FirstName VarChar(100), MiddleName VarChar(100), LastName VarChar(100), AlsoKnown VarChar(100) с каждым столбцом, добавленным к полнотекстовому каталогу, Вы могли использовать запрос:

INSERT INTO @Results (PersonId, Rank, Source)

SELECT PersonId, Rank, 1
FROM ContainsTable(People, FirstName, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

UNION
SELECT PersonId, Rank, 2
FROM ContainsTable(People, MiddleName, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

UNION
SELECT PersonId, Rank, 3
FROM ContainsTable(People, LastName, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

UNION
SELECT PersonId, Rank, 4
FROM ContainsTable(People, AlsoKnown, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

/*
Now that the results from above are in the @Results table, you can manipulate the
rankings in one of several ways, the simplest is to pull the results ordered first by Source then by Rank.  Of course you would probably join to the People table to pull the name fields.
*/

SELECT PersonId
FROM @Results
ORDER BY Source, Rank DESC

/*
A more complex manipulation would use a statement to multiply the ranking by a value above 1 (to increase rank) or less than 1 (to lower rank), then return results based on the new rank.  This provides more fine tuning, since I could make first name 10% higher and middle name 15% lower and leave last name and also known the original value.
*/

SELECT PersonId, CASE Source WHEN 1 THEN Rank * 1.1 WHEN 2 THEN Rank * .9 ELSE Rank END AS NewRank FROM @Results
ORDER BY NewRank DESC

Одна оборотная сторона, Вы заметите, что я не использовал UNION ALL, таким образом, если слово появится больше чем в одном столбце, то разряд не отразит это. Если это - проблема, Вы могли бы использовать UNION ALL и затем удалите дублирующийся идентификатор человека путем добавления всех или части разряда дублирующейся записи к разряду другой записи с тем же идентификатором человека.

7
ответ дан 6 December 2019 в 21:21
поделиться

Разряды бесполезны через индексы, Вы не можете объединить их и ожидать, что результат будет означать что-либо. Числа разряда каждого индекса являются сравнениями яблока/оранжевого/винограда/арбуза/пары, которые не имеют никакого родственника, имеющего в виду содержание WRT других индексов.

Уверенный можно попытаться связать/взвесить/заказать разряды между индексами, чтобы попытаться уклониться от значимого результата, но в конце дня, что результатом является все еще мусор, однако возможно все еще достаточно хороший для предоставления осуществимого решения в зависимости от специфических особенностей ситуации.

По моему мнению, лучшее решение состоит в том, чтобы поместить все данные, которые Вы намереваетесь быть доступными для поиска в единственном индексе/столбец FTS и использовать тот разряд столбцов для упорядочивания вывода.. Даже если необходимо копировать полевое содержание для выполнения результата.

3
ответ дан 6 December 2019 в 21:21
поделиться

Я предполагаю, что возвращенные данные соединены с другими таблицами в рамках Вашей схемы? Я разработал бы Ваш собственный РАЗРЯД на основе столбцов от связанных данных до полнотекстового индекса. Это также обеспечивает гарантируемый уровень точности в значении РАЗРЯДА.

0
ответ дан 6 December 2019 в 21:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: