у меня есть некоторые клиенты с конкретным адресом, который ищет пользователь:
123 универсальных пути
Существует 5 строк в базе данных, которые соответствуют:
ResidentialAddress1
=============================
123 GENERIC WAY
123 GENERIC WAY
123 GENERIC WAY
123 GENERIC WAY
123 GENERIC WAY
я выполняю запрос FT для поиска этих строк. я покажу Вам каждый шаг, поскольку я добавляю больше критериев к поиску:
SELECT ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.ResidentialAddress1, '"123*"')
ResidentialAddress1
=========================
123 MAPLE STREET
12345 TEST
123 MINE STREET
123 GENERIC WAY
123 FAKE STREET
...
(30 row(s) affected)
Хорошо, пока неплохо, теперь добавляя "универсальное" слово:
SELECT ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.ResidentialAddress1, '"123*"')
AND CONTAINS(Patrons.ResidentialAddress1, '"generic*"')
ResidentialAddress1
=============================
123 GENERIC WAY
123 GENERIC WAY
123 GENERIC WAY
123 GENERIC WAY
123 GENERIC WAY
(5 row(s) affected)
Отлично. И теперь i'l добавляют заключительное ключевое слово, что пользователь хочет удостовериться, существует:
SELECT ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.ResidentialAddress1, '"123*"')
AND CONTAINS(Patrons.ResidentialAddress1, '"generic*"')
AND CONTAINS(Patrons.ResidentialAddress1, '"way*"')
ResidentialAddress1
------------------------------
(0 row(s) affected)
Ха? Никакие строки? Что, если я запрашиваю для просто "пути*":
SELECT ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.ResidentialAddress1, '"way*"')
ResidentialAddress1
------------------------------
(0 row(s) affected)
Сначала я думал, что, возможно, это из-за *
, и это требует что корень way
имейте больше символов после него. Но это не верно:
Что, если я удаляю *
только для s&g:
SELECT ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.ResidentialAddress1, '"way"')
Server: Msg 7619, Level 16, State 1, Line 1
A clause of the query contained only ignored words.
Таким образом, можно было бы думать, что Вам просто не разрешают даже искать way
, или один, или как корень. Но это не верно также:
SELECT * FROM Patrons
WHERE CONTAINS(Patrons.*, '"way*"')
AccountNumber FirstName Lastname
------------- --------- --------
33589 JOHN WAYNE
Поэтому подведите итог, пользователь ищет строки, которые содержат все слова:
123 универсальных пути
Который я, правильно, перевожу в WHERE
пункты:
SELECT * FROM Patrons
WHERE CONTAINS(Patrons.*, '"123*"')
AND CONTAINS(Patrons.*, '"generic*"')
AND CONTAINS(Patrons.*, '"way*"')
который не возвращает строк. Скажите мне, что это просто не собирается работать, что это не мой отказ, и SQL Server является сумасшедшим.
Примечание: я освободил индекс FT и восстановил его.
SELECT Lastname, ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.*, '"gen*"')
Lastname ResidentialAddress1
------------------------- ------------------------------
SAVE 123 GENERIC WAY
Genders
SAVE 123 GENERIC WAY
Patron 123 GENERIC WAY
SAVE 123 GENERIC WAY
SAVE 234 GENERIC WAY
SAVE 123 GENERIC WAY
(7 row(s) affected)
Притворство пользователя ввело:
123 универсальных wa
SELECT ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.ResidentialAddress1, '"123*"')
AND CONTAINS(Patrons.ResidentialAddress1, '"generic*"')
AND CONTAINS(Patrons.ResidentialAddress1, '"wa*"')
ResidentialAddress1
------------------------------
(0 row(s) affected)
Настоящая проблема состоит в том, что пользователь вводит в чем-то совершенно допустимом, и они ожидали бы видеть то, что любой человек будет ожидать видеть.
Кто-то попросил все это, это не мой отказ!:
CREATE TABLE [dbo].[Patrons] (
[PatronGUID] uniqueidentifier ROWGUIDCOL NOT NULL ,
[AccountNumber] [bigint] NULL ,
[FirstName] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[MiddleInitial] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Lastname] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[EyeColor] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[HairColor] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Gender] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Birthday] [datetime] NULL ,
[Height] [int] NULL ,
[Weight] [int] NULL ,
[FacialHair] [tinyint] NULL ,
[Nationality] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[IdentifyingMarks] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[DriversLicenseNumber] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[DriversLicenseRegion] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[DriversLicenseCountry] [varchar] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[DriversLicenseExpires] [datetime] NULL ,
[DriversLicenseDateVerified] [datetime] NULL ,
[PassportNumber] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[PassportRegion] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[PassportCountry] [varchar] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[PassportExpires] [datetime] NULL ,
[PassportDateVerified] [datetime] NULL ,
[OtherIdentificationNumber] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[OtherIdentificationRegion] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[OtherIdentificationCountry] [varchar] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[OtherIdentificationType] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[OtherIdentificationExpires] [datetime] NULL ,
[OtherIdentificationDateVerified] [datetime] NULL ,
[ResidentialAddress1] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ResidentialAddress2] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ResidentialAddress3] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ResidentialCity] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ResidentialZipCode] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ResidentialRegion] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ResidentialCountry] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ResidentialPhoneNumber] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[CountryOfResidence] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessAddress1] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessAddress2] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessAddress3] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessCity] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessRegion] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessZipCode] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessCountry] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessName] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[BusinessPhone] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[PositionWithFirm] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[EmployerTelephone] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[MemberCardType] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[PlayerStatusCode] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[AccountType] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[AccountStatus1] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[AccountStatus2] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[IsVIPExchangeRate] [tinyint] NULL ,
[ChangedUserGUID_Depricated] [uniqueidentifier] NULL ,
[ChangedUser] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ChangedDate] [datetime] NULL ,
[ChangedWorkstation] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[PendingUpdates_Depricated] [varchar] (255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Patrons] ADD
CONSTRAINT [DF_Patrons_PatronGUID] DEFAULT (newid()) FOR [PatronGUID],
CONSTRAINT [PK_Patrons] PRIMARY KEY NONCLUSTERED
(
[PatronGUID]
) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
if (select DATABASEPROPERTY(DB_NAME(), N'IsFullTextEnabled')) <> 1
exec sp_fulltext_database N'enable'
GO
if not exists (select * from dbo.sysfulltextcatalogs where name = N'TheFullTextCatalog')
exec sp_fulltext_catalog N'TheFullTextCatalog', N'create'
GO
exec sp_fulltext_table N'[dbo].[Patrons]', N'create', N'TheFullTextCatalog', N'PK_Patrons'
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'FirstName', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'MiddleInitial', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'Lastname', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'EyeColor', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'IdentifyingMarks', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialAddress1', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialAddress2', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialAddress3', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialCity', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialZipCode', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialRegion', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialCountry', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'ResidentialPhoneNumber', N'add', 1033
GO
exec sp_fulltext_column N'[dbo].[Patrons]', N'CountryOfResidence', N'add', 1033
GO
exec sp_fulltext_table N'[dbo].[Patrons]', N'activate'
GO
Вот снимки экрана для парня, который не верил мне:
Запрос, который должен работать, но не делает:
Запрос, который работает, но не полезен:
Запрос, который работает, но не полезен с содержанием доказательства:
Запрос не может быть записан как
CONTAINS(Patrons.*, 'words...')
С тех пор существуют объекты не логически или физически покрыты индексом FT. например, пользовательские запросы для:
6/4/2010 ian boyd 619
Подарки четыре ключевых слова:
Это означает, что они хотят все условия сохраняться с псевдокодом тем, чтобы быть:
WHERE 6/4/2010 is in the row
AND ian is in the row
AND boyd is in the row
AND 619 is in the row
Который переводится в частичный запрос:
WHERE --Keyword 1: 6/4/2010
(
((ChangedDate >= '20100604') AND (ChangedDate < '20100605'))
OR
((LastTransactionDate >= '20100604') AND (LastTransactionDate < '20100605'))
OR
(CONTAINS(Patrons.*, '"6/4/2010*"')
)
AND --Keyword 2: ian
(
CONTAINS(Patrons.*, '"ian*"')
)
AND --Keyword 3: boyd
(
CONTAINS(Patrons.*, '"boyd*"')
)
AND --Keyword 4: 619
(
(AccountNumber IN (SELECT CAST(619 AS bigint)))
OR
(CONTAINS(Patrons.*, '"619*"'))
)
Одна из отвечающих сторон смотрела на упрощенный пример, представленный в исходном вопросе; не реальный мир. Сказать, что неправильно иметь несколько AND
пункты являются nieve.
В сообщении говорится, что «путь» - это стоп-слово, что означает, что оно игнорируется и не индексируется. Вот почему вы можете найти «wayne», но не «way».
Так что нет, это не безумие, и вы тоже. Просто недоразумение.
Возможно, для этого требуется более трех букв алфавита. Попробуйте другое трехбуквенное слово, например gen *
.
Вы, вероятно, использовали системный список стоп-слов при создании индекса FT. Слово путь
случайно находится там. Вы можете увидеть это с помощью этого запроса:
SELECT *
FROM sys.fulltext_system_stopwords
WHERE stopword = 'way'
AND language_id = 1033
Вы можете отключить список стоп-слов или создать собственный, но лучшим решением было бы написать запрос правильно; не используйте несколько предложений WHERE CONTAINS
, объедините их в одно. В противном случае SQL Server не сможет использовать индекс FT так же эффективно.
Вместо этого ваш запрос должен выглядеть так:
SELECT ResidentialAddress1 FROM Patrons
WHERE CONTAINS(Patrons.ResidentialAddress1, '"123*" AND "generic*" AND "way*"')
Если вы сделаете это таким образом, стоп-слово просто игнорируется; он по-прежнему будет возвращать те же результаты, что и, если бы вы не включили термин way *
.
Изменить: только что заметил, что вы пометили этот sql-server-2000
, поэтому первый запрос может не работать. В SQL 2000 это «шумовые слова», и я считаю, что конфигурация является глобальной, у вас нет индивидуальных списков стоп-сигналов. Тем не менее, вы все равно получите результаты, если напишете одно предложение WHERE CONTAINS
вместо нескольких.
Для редактирования шумовых слов в SQL Server 2000 необходимо отредактировать файл для конкретного языка в папке конфигурации SQL Server FTDATA
. Более подробная информация находится здесь: Шумовые слова полнотекстового поиска SQL Server и конфигурации тезауруса .
Решение 1:
Вы хотите попробовать параметр Преобразовать слово шума (SQL 2008) .
Отключение этого параметра должно остановить удаление слов.
sp_configure 'show advanced options', 1
RECONFIGURE
GO
sp_configure 'transform noise words', 1
RECONFIGURE
GO
Редактировать 1:
Надеюсь, может быть что-то подобное для более старых версий MS SQL?
http://www.codinghorror.com/blog/2008/11/stop-me-if-you-think-youve-seen-this-word-before.html
В этом посте Джефф упоминает, что вы можете их отключить.