Search weights
Introduction
How search results are ranked is always a topic for discussion. With Faceted Search, when used in combination with the full-text indexing capabilities of SQL Server, part of this ranking is determined by the results returned from the CONTAINSTABLE query used internally.
The CONTAINSTABLE returns a table with search results, which includes a column named Rank. The Rank column is a value (from 0 through 1000) for each row indicating how well a row matched the search condition. However, this Rank is just the bases for calculating the overall search rank.
Faceted Search offers various options to affect the ranking of the results, based on e.g. SEO Priority, Contenttype weights and/or giving physical fields such as title a higher influence in calculating search ranks, etc. This article discusses the various options.
Query xml
How search ranks are calculated is completely configured (for each source/searchbase separately) within the Query xml, using various local instance vipers. The query snippet below shows an example.
Smartsite SXML | Copy Code |
---|---|
SELECT [KEY] AS Nr, (RANK {sys.iif(this.isbasequery(), "+" + this.seopriority("c.seopriority") + "+" + this.contenttypeweight("c.contenttype_weight") + "+" + this.popularityweight("LOG(ISNULL(pr.visits,1))/LOG(" + sys.eval(maxvisits(), smartlet.number()) + ")"))}) * {this.fieldweight("dbo.fn_tsAgeInDays(c.moddate)", default="c."+this.fieldname()+"_weight")} AS SearchRank, {sys.iif(this.isbasequery() || this.mode()!=SearchQuery, '1', 'NULL')} AS BaseSearch FROM CONTAINSTABLE({this.searchgroupviewname()}, {this.fieldname(default="(QueryData,CTSpecificBinary1)")}, ?:searchterm) JOIN {this.searchgroupviewname()} c WITH (NOEXPAND) ON [KEY]=c.Nr {sys.iif(this.isbasequery(), "LEFT JOIN PageRequests pr ON c.Nr=pr.Nr")} |
In this example, all the available search weight factors are demonstrated. Most of these weight factors are also dependent on relative weights configured within the query xml as well (as childnode of the appropriate searchbase node):
XML | Copy Code |
---|---|
<weights default="1" agefactor="0.05" seopriority="200" contenttypeweight="30" popularityweight="300" /> |
SEO Priority
The search rank for individual items can be adjusted using the this.seopriority() viper within the query definition. The SEO Priority set on an individual item (Low Priority=0, Medium Priority=0.5 and High Priority=1) multiplied with the seopriority relative weight as set on the weights element is added to the calculated search rank.
So, when seopriority attribute is set to 200 (recommended value), an item having High Priority set as SEO priority will score 200 higher on search rank relative to an item having Low Priority.
Notice that you have to specify the fieldname and appropriate prefix as argument of the viper:
Smartsite SXML | Copy Code |
---|---|
this.seopriority("c.seopriority") |
To limit the number of JOINS necessary, the view for a particular search group (e.g. vwTsContentPUB) always include the field seopriority, with a default value set to 0.5 on items for which SEO Priority hasn't been set.
Contenttype Weight
Search ranks for items of a particular contenttype can be adjusted using the this.contenttypeweight() viper within the query definition. For individual contenttypes and for each Search Group separately, a contenttype-specific weight factor (between 0 and 10) can be set using the action Contenttype Weights within the Faceted Search Console.
The contenttypeweight attribute on the weights element defines the relative search rank weight (e.g. 30), which is multiplied with the item's contenttype weight (which defaults to 5 if for the item's contenttype no specific weight has been configured).
As is the case with seopriority, the view for a particular search group includes the contenttype_weight field (to limit the number of necessary JOINS), which reflects the item's contenttype weight setting. Therefore, the viper should be specified as:
Smartsite SXML | Copy Code |
---|---|
this.contenttypeweight("c.contenttype_weight") |
Popularity Weight
Another mechanism to adjust search ranks is applying the popularity weight. This weight factor accounts for giving popular items (based on the number of visits) a higher search rank than less popular items. You might think of this being a self-fulfilling prophecy, but when using a logarithmic scale that's certainly not the case.
The viper to use popularity weight should look like:
Smartsite SXML | Copy Code |
---|---|
this.popularityweight("LOG(ISNULL(pr.visits,1))/LOG(" + sys.eval(maxvisits(), smartlet.number()) + ")")) |
(The maxvisits() is a translation which retrieves and caches the maximum number of visits.)
As said, it takes the number of visits into account (pr.visits), so a JOIN to the table PageRequest is also needed. This is achieved with appending this statement to the query:
Smartsite SXML | Copy Code |
---|---|
{sys.iif(this.isbasequery(), "LEFT JOIN PageRequests pr ON c.Nr=pr.Nr")} |
The popularityweight attribute on the weights element defines the relative search rank weight which must be applied. So, the value of this attribute multiplied with the result of the statement shown above makes up the popularity weight for individual items.
Age Factor
Items which haven't been changed for many months could be considered as less relevant to a search request than items that have been changed recently. This can be taken into account using the age factor.
The age factor uses the database function fn_tsAgeInDays and is implemented within the query xml using the this.fieldweight() viper (see below).
Field Weight
For specific (physical) fields, for each Search Group separately, you can define search weights using the Field Weights action within the Faceted Search Console. This way, items with matches on search term(s) within e.g. the title will have a higher search rank.
The this.fieldweight() viper call to accomplish this is:
Smartsite SXML | Copy Code |
---|---|
{this.fieldweight("dbo.fn_tsAgeInDays(c.moddate)", default="c."+this.fieldname()+"_weight")} |
Notice that these field weights will be part of the Search Group's view, hence they will only be applied for fulltext queries.
When you want to apply field weights for native queries, you need to specify them within the query xml using one or more field nodes within the weights node..