Equivalent of like '%%' for contains(column-name,'%%') - sql-server

This is my following query:
select Top 100 * from TweetEntity where contains (HashTag,'')
I get an error saying.
Null or empty full-text predicate.
Then I changed my query :
select Top 100 * from TweetEntity where contains (HashTag,'%%'). I got no results.
I expected it to run.
What is the equivalent of (using contains):
select Top 100 * from TweetEntity where HashTag like '%%' ?
how ever this works returning records:
select Top 100 * from TweetEntity where contains(HashTag,'gaza')
where as
select Top 100 * from TweetEntity where contains(HashTag,'a') - this doesnot return any records.

Full text Search is a feature to do Language Specific Search.
The search may ignore the literal strings in the data and search for a specific word in a language , (Inflectional forms of a specific word, Synonymous etc) which is specific to a language.
Here in your query you are looking for the Letter "A" which isnt a word in english, its an alphabet but alone it doesn't mean anything. It is more like a pattren in a string for that purpose you should use LIKE key word along with wildcard % which will bring back the string value James W Brown.
On the other hand if you a wanted to use FTS to find all the possible James in your database then FTS can be handy. By doing a THESAURUS search on James which will bring back Jim, Jimmy, Jimmie etc but then again you will have to edit the XML files under FDData for a specific language to make this happen.
A , The etc are considered to be noise words and they are ignored in FTS.

You will never be able to search for "a". This is going to be included in the default stop-word list for English along with other common superfluous words such as "an", "the", etc. If you want to search for "a" you will need to create a custom stop-word list that excludes that.

Related

MS SQL : Full Text Search Results are not relevant

I am trying MS SQL Full Text Query on single column.
For this I am using "FREETEXTABLE" function.
When I query "Horse ride" the result set contains videos where title contain the word "ride".
No wonder that when using FREE or "FREETEXTTABLE" the process is to break query string
into words, create inflectional words and that is how the result set get generated.
So my question is if this is the process, why the result set have no video where the "horse" word is
present (I have videos in DB where videos title contains the "horse" word).
Is it because the word breaker gives preference to "verbs" ?
Please comment on how "word breaker" and "stemmer" works for English language.
Links where I could find grate details about "word breaker" and "stemmer" will also be
help full.
This is very important for me to get relevant results every time.
Thank you.
Full text search filters the noise words and punctuations and you have the flexibility of adding more noise words to the default list of noise words. But to manipulate verbs, inflectional or synonyms we can make use of different functions in where clause.
In your case if you are looking for fields where the word "Horse" AND "ride" exists you can simply make use of Contains function, something like this....
SELECT ColumnName
FROM TableName
WHERE Contains(ColumnName, '"horse" AND "ride"')
If you are looking for values where there is word "Horse" and any inflectional form of "ride" say like ride, riding. You can use something like this ....
SELECT ColumnName
FROM TableName
WHERE Contains(ColumnName, '"horse"') AND CONTAINS(ColumnName, 'FORMSOF(INFLECTIONAL, ride)')

SQL Server Full Text Search - Is it possible to search in the middle of a word?

I have full text search on my database.
Is it possible to search in the middle of a word for some text?
For example, I have a column Description that contains the following text:
Revolution
Is it possible to search for 'EVO' and have it find it in the word Revolution or am I stuck doing a LIKE:
SELECT * FROM Table WHERE Description LIKE '%EVO%'
Is there a FTS equivalent of the above query?
EDIT
I want to make it clear what I am trying to ask because it appear a few people might be confused. I believe that SQL Server FTS can only search at the beginning of the word (prefix search). So if I query like:
SELECT * FROM Table WHERE CONTAINS(Description, '"Revo*"')
Then it will find the word Revolution. I want to know if it is possible at all to search something in the MIDDLE of the word. Not at the end. Not at the beginning. From what it looks like this is not possible and it makes sense because how would SQL server index this, but I just wanted to be certain.
This looks like it has come up before and the short answer was "No".
Previous thread
You can use CONTAINS. See this link
Full text catalog/index search for %book%
The only way to do this search is to add a "rotational" break down of the words.
As an exemple, the word "locomotion" will be break down into 9 new "word" like :
"ocomotion"
"comotion"
"omotion"
"motion"
"otion"
"tion"
"ion"
"on"
"n"
So now you can put this table into the Full Text Search (or create à new columns with all these parts of the word) to find it quickly.
I wrote a paper to do that without FTS (but it is in french) :
https://blog.developpez.com/sqlpro/p13123/langage-sql-norme/like-mot-ou-les-index-rotatifs
You can use CONTAINS instead of LIKE.
SELECT *
FROM Table
WHERE CONTAINS(Description, '"EVO*"')

Exclude apostrophes from SQL Server Full Text Search

I would like to know how to exclude apostrophes from being indexed in full text search.
For example, if someone enters a search term for "o'brien" or for "obrien" I would want it to match all cases where someone's name matches either "O'Brien" or "OBrien".
However, if I search on:
select * from MyTable where contains (fullName, '"o''Brien*"')
It returns only ones with an apostrophe.
But if I do:
select * from MyTable where contains (fullName, '"oBrien*"')
It only returns the ones without an apostrophe.
In short, I want to know if it is possible for FTS to index both "O'Brien" and "OBrien" as "obrien" so that I can find both.
While the solution:
select * from MyTable where contains (fullName, '"oBrien*" OR "o''Brien*"')
would work, however, I can't make that assumption if the user entered "obrien".
I'm looking for a solution that works both on SQL Server 2005 and 2008.
depending on how much space you have, you could add another column
fullName_noPunctuation
containing only the alpha characters of the name, strip punctuation from your search criteria, and search the punctuation-free column instead.

Apostrophes and SQL Server FT search

I have setup FT search in SQL Server 2005 but I cant seem to find a way to match "Lias" keyword to a record with "Lia's". What I basically want is to allow people to search without the apostrophe.
I have been on and off this problem for quite some time now so any help will really be a blessing.
EDIT 2: just realised this doesn't actually resolve your problem, please ignore and see other answer! The code below will return results for a case when a user has inserted an apostrophe which shouldn't be there, such as "abandoned it's cargo".
I don't have FT installed locally and have not tested this - you can use the syntax of CONTAINS to test for both the original occurrence and one with the apostrophe stripped, i.e.:
SELECT *
FROM table
WHERE CONTAINS ('value' OR Replace('value', '''',''))
EDIT: You can search for phrases using double quotes, e.g.
SELECT *
FROM table
WHERE CONTAINS ("this phrase" OR Replace("this phrase", '''',''))
See MSDN documentation for CONTAINS. This actually indicates the punctuation is ignored anyway, but again I haven't tested; it may be worth just trying CONTAINS('value') on its own.
I haven't used FT, but in doing queries on varchar columns, and looking for surnames such as O'Reilly, I've used:
surname like Replace( #search, '''', '') + '%' or
Replace( surname,'''','') like #search + '%'
This allows for the apostrophe to be in either the database value or the search term. It's also obviously going to perform like a dog with a large table.
The alternative (also not a good one probably) would be to save a 2nd copy of the data, stripped of non-alpha characters, and search (also?) against that copy. So there original would contain Lia's and the 2nd copy Lias. Doubling the amount of storage, etc.
Another attempt:
SELECT surname
FROM table
WHERE surname LIKE '%value%'
OR REPLACE(surname,'''','') LIKE '%value%'
This works for me (without FT enabled), i.e. I get the same results when searching for O'Connor or OConnor.

How do you get leading wildcard full-text searches to work in SQL Server?

Note: I am using SQL's Full-text search capabilities, CONTAINS clauses and all - the * is the wildcard in full-text, % is for LIKE clauses only.
I've read in several places now that "leading wildcard" searches (e.g. using "*overflow" to match "stackoverflow") is not supported in MS SQL. I'm considering using a CLR function to add regex matching, but I'm curious to see what other solutions people might have.
More Info: You can add the asterisk only at the end of the word or phrase. - along with my empirical experience: When matching "myvalue", "my*" works, but "(asterisk)value" returns no match, when doing a query as simple as:
SELECT * FROM TABLENAME WHERE CONTAINS(TextColumn, '"*searchterm"');
Thus, my need for a workaround. I'm only using search in my site on an actual search page - so it needs to work basically the same way that Google works (in the eyes on a Joe Sixpack-type user). Not nearly as complicated, but this sort of match really shouldn't fail.
Workaround only for leading wildcard:
store the text reversed in a different field (or in materialised view)
create a full text index on this column
find the reversed text with an *
SELECT *
FROM TABLENAME
WHERE CONTAINS(TextColumnREV, '"mrethcraes*"');
Of course there are many drawbacks, just for quick workaround...
Not to mention CONTAINSTABLE...
The problem with leading Wildcards: They cannot be indexed, hence you're doing a full table scan.
It is possible to use the wildcard "*" at the end of the word or phrase (prefix search).
For example, this query will find all "datab", "database", "databases" ...
SELECT * FROM SomeTable WHERE CONTAINS(ColumnName, '"datab*"')
But, unforutnately, it is not possible to search with leading wildcard.
For example, this query will not find "database"
SELECT * FROM SomeTable WHERE CONTAINS(ColumnName, '"*abase"')
To perhaps add clarity to this thread, from my testing on 2008 R2, Franjo is correct above. When dealing with full text searching, at least when using the CONTAINS phrase, you cannot use a leading , only a trailing functionally. * is the wildcard, not % in full text.
Some have suggested that * is ignored. That does not seem to be the case, my results seem to show that the trailing * functionality does work. I think leading * are ignored by the engine.
My added problem however is that the same query, with a trailing *, that uses full text with wildcards worked relatively fast on 2005(20 seconds), and slowed to 12 minutes after migrating the db to 2008 R2. It seems at least one other user had similar results and he started a forum post which I added to... FREETEXT works fast still, but something "seems" to have changed with the way 2008 processes trailing * in CONTAINS. They give all sorts of warnings in the Upgrade Advisor that they "improved" FULL TEXT so your code may break, but unfortunately they do not give you any specific warnings about certain deprecated code etc. ...just a disclaimer that they changed it, use at your own risk.
http://social.msdn.microsoft.com/Forums/ar-SA/sqlsearch/thread/7e45b7e4-2061-4c89-af68-febd668f346c
Maybe, this is the closest MS hit related to these issues... http://msdn.microsoft.com/en-us/library/ms143709.aspx
One thing worth keeping in mind is that leading wildcard queries come at a significant performance premium, compared to other wildcard usages.
Note: this was the answer I submitted for the original version #1 of the question before the CONTAINS keyword was introduced in revision #2. It's still factually accurate.
The wildcard character in SQL Server is the % sign and it works just fine, leading, trailing or otherwise.
That said, if you're going to be doing any kind of serious full text searching then I'd consider utilising the Full Text Index capabilities. Using % and _ wild cards will cause your database to take a serious performance hit.
Just FYI, Google does not do any substring searches or truncation, right or left. They have a wildcard character * to find unknown words in a phrase, but not a word.
Google, along with most full-text search engines, sets up an inverted index based on the alphabetical order of words, with links to their source documents. Binary search is wicked fast, even for huge indexes. But it's really really hard to do a left-truncation in this case, because it loses the advantage of the index.
As a parameter in a stored procedure you can use it as:
ALTER procedure [dbo].[uspLkp_DrugProductSelectAllByName]
(
#PROPRIETARY_NAME varchar(10)
)
as
set nocount on
declare #PROPRIETARY_NAME2 varchar(10) = '"' + #PROPRIETARY_NAME + '*"'
select ldp.*, lkp.DRUG_PKG_ID
from Lkp_DrugProduct ldp
left outer join Lkp_DrugPackage lkp on ldp.DRUG_PROD_ID = lkp.DRUG_PROD_ID
where contains(ldp.PROPRIETARY_NAME, #PROPRIETARY_NAME2)
When it comes to full-text searching, for my money nothing beats Lucene. There is a .Net port available that is compatible with indexes created with the Java version.
There's a little work involved in that you have to create/maintain the indexes, but the search speed is fantastic and you can create all sorts of interesting queries. Even indexing speed is pretty good - we just completely rebuild our indexes once a day and don't worry about updating them.
As an example, this search functionality is powered by Lucene.Net.
Perhaps the following link will provide the final answer to this use of wildcards: Performing FTS Wildcard Searches.
Note the passage that states: "However, if you specify “Chain” or “Chain”, you will not get the expected result. The asterisk will be considered as a normal punctuation mark not a wildcard character. "
If you have access to the list of words of the full text search engine, you could do a 'like' search on this list and match the database with the words found, e.g. a table 'words' with following words:
pie
applepie
spies
cherrypie
dog
cat
To match all words containing 'pie' in this database on a fts table 'full_text' with field 'text':
to-match <- SELECT word FROM words WHERE word LIKE '%pie%'
matcher = ""
a = ""
foreach(m, to-match) {
matcher += a
matcher += m
a = " OR "
}
SELECT text FROM full_text WHERE text MATCH matcher
% Matches any number of characters
_ Matches a single character
I've never used Full-Text indexing but you can accomplish rather complex and fast search queries with simply using the build in T-SQL string functions.
From SQL Server Books Online:
To write full-text queries in
Microsoft SQL Server 2005, you must
learn how to use the CONTAINS and
FREETEXT Transact-SQL predicates, and
the CONTAINSTABLE and FREETEXTTABLE
rowset-valued functions.
That means all of the queries written above with the % and _ are not valid full text queries.
Here is a sample of what a query looks like when calling the CONTAINSTABLE function.
SELECT RANK , * FROM TableName ,
CONTAINSTABLE (TableName, *, '
"*WildCard" ') searchTable WHERE
[KEY] = TableName.pk ORDER BY
searchTable.RANK DESC
In order for the CONTAINSTABLE function to know that I'm using a wildcard search, I have to wrap it in double quotes. I can use the wildcard character * at the beginning or ending. There are a lot of other things you can do when you're building the search string for the CONTAINSTABLE function. You can search for a word near another word, search for inflectional words (drive = drives, drove, driving, and driven), and search for synonym of another word (metal can have synonyms such as aluminum and steel).
I just created a table, put a full text index on the table and did a couple of test searches and didn't have a problem, so wildcard searching works as intended.
[Update]
I see that you've updated your question and know that you need to use one of the functions.
You can still search with the wildcard at the beginning, but if the word is not a full word following the wildcard, you have to add another wildcard at the end.
Example: "*ildcar" will look for a single word as long as it ends with "ildcar".
Example: "*ildcar*" will look for a single word with "ildcar" in the middle, which means it will match "wildcard". [Just noticed that Markdown removed the wildcard characters from the beginning and ending of my quoted string here.]
[Update #2]
Dave Ward - Using a wildcard with one of the functions shouldn't be a huge perf hit. If I created a search string with just "*", it will not return all rows, in my test case, it returned 0 records.

Resources