Полнотекстовый поиск поля URL sql server
цель: вернуть все URL-адреса, начинающиеся с "https://mywebsite.domain.com/as/product/4/"
дано:
- применяется полнотекстовый поиск в поле URL.
- SQL Server edition: 2014.
- 20+ миллионов строк
URL-адресом
https://mywebsite.domain.com/as/product/1/production
https://mywebsite.domain.com/as/product/2/items
https://mywebsite.domain.com/as/product/1/affordability
https://mywebsite.domain.com/as/product/3/summary
https://mywebsite.domain.com/as/product/4/schedule
https://mywebsite.domain.com/as/product/4/resources/summary
запрос 1:
WHERE CONTAINS (URL, 'https://mywebsite.domain.com/as/product/4')
результат:
All records returned
запрос 2 (добавил "*" после прочтения в MSDN статья)
WHERE CONTAINS (URL, '"https://mywebsite.domain.com/as/product/4*"')
результат:
No records returned
любая помощь была бы весьма признательна.
5 ответов
можно использовать CONTAINS
С LIKE
подзапрос для сопоставления только начала:
SELECT *
FROM (
SELECT *
FROM myTable WHERE CONTAINS (URL, '"https://mywebsite.domain.com/as/product/4/"')
) AS S1
WHERE S1.URL LIKE 'https://mywebsite.domain.com/as/product/4/%'
таким образом,медленно LIKE
запрос оператора будет выполняться для меньшего набора записей
EDIT1: (если WHERE CONTAINS (URL, '"https://mywebsite.domain.com/as/product/4/"')
Не фильтрует значения)
после долгих поисков. проблема в /
. Косая черта не содержится в файле слов шума, но я думаю, что она классифицируется как разделитель или разбиение слов и поэтому поиск невозможен.
читать эти темы:
EDIT2:
я нашел одно предлагаемое решение, которое
/
рассматривается как английский wordbreaker вы можете изменить его от Реестр
- перейдите к значениям реестра
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\<InstanceRoot>\MSSearch\Language\eng
иHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\<InstanceRoot>\MSSearch\Language\enu
- очистить значение для WBreakerClass.
Sql server рассмотреть https://mywebsite.domain.com/as/product/4
как одно слово.
Примечание: выше обоих путей я взял, предполагая, что вы используете английский язык в качестве Word breaker.
подробнее о Word Breaker в этом раздел MSDN
использовать Like
оператор:
WHERE URL LIKE 'https://mywebsite.domain.com/as/product/4%'
на %
является подстановочным. Это должно возвращать все записи, которые начинаются с шаблона, совпадающего с первым подстановочным знаком %
.
при условии, что вы всегда ищете начало строки, это гарантирует, что оптимизатор может использовать индекс. Я предполагаю, что URL-адрес VARCHAR
Declare @p varchar(500) ='https://mywebsite.domain.com/as/product/4'
Declare @maxChar char(1);
select @maxChar = max(ch)
from (
select top(256) ch = char(row_number() over(order by (select null)) - 1)
from sys.all_objects) t;
select @maxChar;
-- ..
WHERE URL > @p AND URL < @p + @maxChar
при сравнении строк Sql server добавляет конечные пробелы к более коротким. См.https://support.microsoft.com/en-us/kb/316626 . Согласно http://www.ietf.org/rfc/rfc1738.txt , http://www.ietf.org/rfc/rfc1738.txt все разрешенные символы URL больше, чем пробел. Итак, параметр поиска,'https://mywebsite.domain.com/as/product/4'
для например, будет меньше любого URL, который начинается с этого параметра и превышает длину параметра.
для подобных проблем я привык к двум решениям, в зависимости от ваших потребностей, в основном от performaces или ресурсов или параллелизма.. и т. д. и т. п..
The LIKE
оператор может быть вашим лучшим другом также с очень большими таблицами.
индексации
Прежде всего, вам нужно проиндексировать столбец url, работая с 20 + миллионами записей это непростая задача,
индексация это может стоить 1.5 - 2.0 Гб дискового пространства,
но вы получите свой запрос в кратчайшие сроки (миллисекунды)
с индексом на столбце для поиска,LIKE FixedPattern+%
выполняется с индексом seek,вы не можете улучшить его дальше.
первый вариант:
CREATE NONCLUSTERED INDEX [IX_URL] ON [url_table] ([url]);
DECLARE @Domain VARCHAR(100) = 'https://mywebsite.domain.com/'
DECLARE @Path VARCHAR(100) = 'as/product/'
DECLARE @Product VARCHAR(20) = '4'
DECLARE @LikeAll VARCHAR(100) = @Domain + @Path + @Product + '/%'
SELECT url
FROM url_table
WHERE url LIKE @LikeAll
второй вариант
Второй вариант немного сложный, но очень эффективный.
Вы сказали, что протокол и домен url исправлены, и вам нужно что-то искать после.
Ниже приведен метод, вы можете настроить это соответствует вашим потребностям.
Идея состоит в том, чтобы добавить виртуальный (вычисляемый) столбец в таблицу url, а затем добавить на него индекс.
Это значительно уменьшит размеры индекса и улучшит производительность запросов за счет очень небольших затрат на вычисления в insert/update
ALTER TABLE url_table ADD path AS (SUBSTRING(url, 30, 4000));
CREATE NONCLUSTERED INDEX [IX_PATH] ON [url_table] ([path]);
DECLARE @Domain VARCHAR(100) = 'https://mywebsite.domain.com/'
DECLARE @Path VARCHAR(100) = 'as/product/'
DECLARE @Product VARCHAR(20) = '4'
DECLARE @LikeMid VARCHAR(100) = @Path + @Product + '/%'
select @Domain + _path -- pay attention!!
FROM url_table
WHERE url LIKE @SrcAll
обратите внимание, мы выбираем @Domain + _path вместо url, чтобы избежать доступа к таблице и работать только с индексными данными.
Если вам нужны другие столбцы в url_table, ваш лучший вариант is
declare @l table (id int primary key)
insert into @l
select id
from url_table
where _path like @LikeMid
select url
from url_table
where id in (select id from @l)
очень быстро
Третий способ
Это вариант второго.
В вашем примере данных я вижу, что путь содержит /product/
затем номер, и я предполагаю, что это номер продукта.
Возможно, вы можете рассмотреть следующее
ALTER TABLE url_table ADD _product AS (cast(substring(url,nullif(CHARINDEX('/product/',url,29)+9,9), CHARINDEX('/',url,nullif(CHARINDEX('/product/',url,29)+9,9))-nullif(CHARINDEX('/product/',url,29)+9,9)) as bigint));
CREATE NONCLUSTERED INDEX [IX_PRODUCT] ON [url] ([_product]);
select id, url
from url_table
where _product = 4
это произведет вычисляемый столбец с номером продукта типа integer, индекс будет только 500Mb и запросы на целых числах будут супер быстрыми.
Также надбавки к выберите все столбцы из url_table очень мало, поэтому вы можете SELECT *
почти без проблем выступлений.
С. П. Вы можете удалить свой полнотекстовый индекс и сэкономить место и ресурсы..