-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e970549
commit fbba1e4
Showing
18 changed files
with
364 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
fbba1e4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Full-Text Search, Snippets and Highlight in
SearchControl
In this post I want to present three unrelated features that complement each other:
SearchControl
)SearchControl
SearchControl
SearchControl
All three are meant to improve the experience of searching by text, either by making it faster, or showing the results in a more user-friendly way.
What is Full-Text Search.
Full-Text Search is a relatevly mature feature of SQL Server that has taken way too long to come into Signum Framework, and it can be a good alternative to more heavyweight solutions like
ElasticSearch
for most of the cases.The idea is to index all the words found in a document, and when a query is made, it will be splitted into words and search the document where this words are found.
This makes the query much faster but also means that, by default, searching by
"Signu"
won't find results for"Signum"
because they are different words.This index is called Full-Text index and requires:
ID
) to reference the results.There is only one Full-Text index per table and all the selected string columns of the table will be stored together in the same Full-Text index. You can imagine as a table with the following structure.
Signum
)The topic is explain in more depth here, but let me do a small explanation of some tricky concepts.
Once you have a Full-Text Index, SQL Server allows you to query it using two functions:
CONTAINS
andFREETEXT
. Both functions return a boolean.CONTAINS(columns, searchCondition)
: Returns True if the column or columns match the searchCondition.columns
should be one or more expressions referencing a database column, with implicit or explicit table alias (p.Name
or justName
). Only columns of the same table are allowed, and you search in all the full-text indexed columns usingp.*
. If more than one column is used, use parenthesys like in a tuple:CONTAINS((p.Notes, p.Qualifications), "C#")
searchCondition
string containing a mini-SDL to define the right match, allowing boolean operators and quotes for words that should appear in the same order (("Signum Framework" OR LINQ OR TypeScript OR JavaSCript) AND NOT Microservice
).Example:
FREETEXT(columns, freeText)
: Returns True if the column or columns have some fuzzy similarity with the text written infreeText
.columns
similar toCONTAINS
columns
freeText
unestructured sentence that should be similar to the results. Example: `"Signum Framework TypeScript"Example:
This two function have the limitation that, by returning a
boolean
, do not allow ranking the results by better matching, that's why another two functions are needed:CONTAINSTABLE
andFREETEXTTABLE
.The
-TABLE
variants allow you direct access to the full-text index, returning a view.CONTAINSTABLE(table, columns, searchCondition)
: Returns a view withRANK
andKEY
.Key
is the unique column (theID
) while RANK is a value that is bigger the better the result is.table
: The name of the table containing the full-text index (dbo.Person
)columns
: The column of columns (in a tuple). Use*
for all columns. Note that this are column names defined intable
, not expression referencing a column with an optional alias.searchCondition
Identical toCONTAINS
searchCondition
.top_n_by_rank
: Optional, limits to N resultsFREETEXTTABLE(table, columns, searchCondition)
: Similar toCONTAINSTABLE
but withfreeText
instead ofsearchCondition
.Registering a Full-Text Search Index
Registering is as simple as using
WithFullTextIndex
:Since Full-Text Index is not supported by default in SQL Server Express, maybe you want to include it conditionally:
The Synchronizer / SQL Migrations will take care of creating the Full-Text index and the Full-Text catallog if necessary (can not be created transactionally!).
Full-Text Functions in LINQ Provider
The LINQ Provider contains methods that mimic the SQL Server counterparts:
For example:
Is equivalent to:
And:
You can find more examples in Signum.Test
FullTextSearchTest.cs
Full-Text Operators in SearchControl Filters
Knowing how the integration of Full-Text in the LINQ Provider works is usefull if you are building a custom Product Catallog or something like this,
but in Sigum apps most of the queries are made through the Search Control, so we have also build a firs-class integration.
Whenever a columns has a full-text index, two new filter operations are available:
ComplexCondition
(related toCONTAINS
SQL method) andFreeText
.If you combine multiple
CONTAINS
for different columns of the same table in anOR
group with a pinned filter, the query will be simplified.So instead of
The query will automatically be:
Additionally, you can add a new QueryToken to columns or orders called
MatchRank
, available for every column in a full-text search.Whenever this token is found as a column and/or as an order, then the
ComplexCondition
andFreeText
filters will be promoted to useCONTAINSTABLE
/FREETEXTTABLE
instead, and the rank returned will be used for this column or order.Text Snippet in SearchControl
Full-Text search is useful for columns with long texts (
NVARCHART(MAX)
), but you don't want to spit all the content to the user in the SearchControl.For this reasons by default any string column with more than 200 charactes (with or without full-text search) get an additional
MatchSnippet
query token that will return a Google-Like summary of the document, only showing the sentences where the macthing words are found.The algorithm understands keywords using the new filter operations (
ComplexCondition
andFreeText
) as well as the traditional ones (Contains
,StartsWith
, etc..) and is executed in the server side.As a bonus, ordering by a
MatchSnippet
(ascending) is automatically transformed to ordering by aMatchRank
(descending).Highlight in SearchControl
Finally, to improve the UI even more, the search terms are now highlighted in bold in the search results.
This feature is avaiable for any string column, not only the big ones, so I expect it to be the more popular one.
Also is able to detect filters with exactly the same token (
Name
), or similar tokens with the same property route (Entity.Name
vsName
) and understands theToStringExpresion
(Name
vs[ToStr]
).The highlight algorithm also understands keywords using the new filter operations (
ComplexCondition
andFreeText
) as well as the traditional ones (Contains
,StartsWith
, etc..) but this time is executed in the client side.You can highlight you custom
CellFormatter
/renderLite
using the newTextHighlighter
class.Example from
formatRules
inFinder
:Conclusion
The
SearchControl
continues to be a flexible component for deterministic filtering of relational data, but with the new Full-Text Search operators, Text Snippets, and Text Hightlights now it has gained some super powers for building a more google-like UI, where all the search is text based, and the results need to be ranked.Enjoy!
fbba1e4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent, very useful feature 🥇