Click here to Skip to main content
15,884,537 members
Articles / All Topics
Technical Blog

Hit Highlight for SQL Server Full Text Search

Rate me:
Please Sign up or sign in to vote.
3.57/5 (3 votes)
20 Jul 2013CPOL 20.4K   5   5
Hit highlight for SQL Server full text search.

SQL Server Full Text Search finds documents but does not help you to build highlighted extracts of documents. If you want you still can do it yourself. The algorithm is the following:

  1. find documents using Full Text Search
  2. load contents of each document
  3. parse the search phrase into words
  4. build extract by finding search terms in the document body

The function can look like this:

SQL
CREATE FUNCTION [dbo].[HighLightSearch](@contents NVARCHAR(MAX), 
  @searchTerm NVARCHAR(4000), @style NVARCHAR(4000), @maxLen INT)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @c NCHAR(1)
    DECLARE @len INT = 0
    DECLARE @l INT = 0
    DECLARE @p INT = 0
    DECLARE @prevPos INT = 0
    DECLARE @margin INT
    DECLARE @term NVARCHAR(4000)
    DECLARE @retval NVARCHAR(MAX) = ''
    
    DECLARE @positions TABLE
    (
        S INT,
        L INT
    )

    -- find all occurrences of the search term

    DECLARE cur1 CURSOR FOR
    SELECT display_term FROM sys.dm_fts_parser(
       N'FORMSOF(FREETEXT, "' + @searchTerm + '")', 1033, 0, 1)
    
    OPEN cur1
    FETCH NEXT FROM cur1 INTO @term

    WHILE @@FETCH_STATUS = 0
    BEGIN
        WHILE 1 = 1
        BEGIN
            SET @p = CHARINDEX(@term, @contents, @p)
            IF @p <= 0 BREAK
            
            SET @l = LEN(@term)
            
            IF @p > 0 BEGIN
                SET @c = SUBSTRING(@contents, @p - 1, 1)
                IF @c <> ' ' AND @c <> NCHAR(9) AND 
                   @c <> NCHAR(13) AND @c <> NCHAR(10) BREAK
            END
            
            INSERT INTO @positions (S, L) VALUES(@p, @l)
            SET @p = @p + LEN(@term)
        END
        
        FETCH NEXT FROM cur1 INTO @term   
    END   

    CLOSE cur1
    DEALLOCATE cur1
    
    -- build the result string
    
    DECLARE cur2 CURSOR FOR
    SELECT S, MAX(L)
    FROM @positions
    GROUP BY S
    ORDER BY S 
    
    SET @margin = LOG(@maxLen) * 5
    IF @margin > @maxLen / 4 SET @margin = @maxLen / 4
    SELECT @prevPos = MIN(S) - @margin FROM @positions

    OPEN cur2
    FETCH NEXT FROM cur2 INTO @p, @l

    WHILE @@FETCH_STATUS = 0 AND @len < @maxLen
    BEGIN
        SET @retval = @retval + SUBSTRING(@contents, @prevPos, @p - @prevPos)
        SET @retval = @retval + '<span style="' + @style + '">' + SUBSTRING(@contents, @p, @l)  + '</span>'
        SET @len = @len + @p - @prevPos + @l
        SET @prevPos = @p + @l
        
        FETCH NEXT FROM cur2 INTO @p, @l
    END   

    CLOSE cur2
    DEALLOCATE cur2

    SET @margin = LOG(@maxLen) * 5
    IF @margin + @len < @maxLen SET @margin = @maxLen - @len
    IF @margin > 0 SET @retval = @retval + SUBSTRING(@contents, @prevPos, @l)

    RETURN '...' + @retval + '...'
END

Being called with the following arguments...

SQL
SELECT dbo.HighLightSearch(
'40 Liters glass fish tank with lid, hangon filter and air pump. 
' I will throw in 6 guppies for you to start up the tank.  Great for kids, beginner or as a present.
The tank has no leaks or scratches, sell due to upgraded to a bigger tank.
Please note, it doesn''t come with a heater.
If you have any questions, please contact me.',
'leak or scratch',
'background-color:yellow;font-weight:bold',
50)

... it returns the following:

...tank has no leaks or scratches, sell du...

And this is how you can use this function in stored proc:

SQL
ALTER PROCEDURE [dbo].[Search]
(
    @searchTerm nvarchar(100),
    @style nvarchar(100) = 'font-weight:bold; background-color:yellow',
    @maxLen INT = 100
)
AS 
BEGIN
    SELECT 
        Id, 
        Name,
        dbo.HighLightSearch(Description, @searchTerm, @style, @maxLen) AS Extract 
    FROM Documents
    WHERE FREETEXT (Description, @searchTerm);
END

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionI found something much better Pin
Member 1135949811-May-18 20:51
Member 1135949811-May-18 20:51 
QuestionNegated Terms Pin
tfranzese1-May-15 17:53
tfranzese1-May-15 17:53 
Questionenhancements for accents incensitive and case incensitive Pin
Member 61912725-Feb-15 3:21
Member 61912725-Feb-15 3:21 
QuestionThis only works if content is stored in clear text Pin
bw21127330-Oct-13 3:19
bw21127330-Oct-13 3:19 
GeneralMy vote of 1 Pin
Marius Bancila12-Aug-13 3:01
professionalMarius Bancila12-Aug-13 3:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.