SharePoint 2010 introduces a new feature to allow a user to rate content within the sites. Depicted by five stars the user can rate content and these ratings are collated to provide the average rating for the item. Displaying content based on ratings can assist users determining the quality of content easily. Ratings will also help content authors understand which content is considered to be higher quality by the readers.
The native rating user interface is a collection of five stars. After a user selects the desired rating it is submitted and averaged with the other ratings for the content. The ratings are processed by a timer job process so there is some small delay.
By default ratings can be configured on lists and libraries and also added to page layouts. They also get fed into the Activity Feed system as rating activities. These add some great user focused features, but in my opinion there is a missing piece.
Search….
So I got thinking having seen some articles about additional search managed properties. Seeing as the average rating and rating count are both columns added to the list/library I decided to investigate whether it was possible to index and therefore present the rating within the search results.
So here the journey of rating discovery begins…
Adding ratings to lists or libraries
Before we can investigate getting ratings into the search experience we need to get rating up and running on some content. So lets go ahead and create a document library as our demo content. Upload numerous documents into the library (at least five) so that we have some content to rate.
So that’s the content ready for rating so what next?
- Browse to the library.
- From the ‘Library’ ribbon click the ‘Library settings’ button.
- Under the general heading click the ‘Rating settings’ link.
- Under the ‘Allow items in this list to be rated’ click yes and ‘Ok’.
This adds two columns to the library. The ‘Rating (0-5)’ and ‘Number of Ratings’. By default the Rating column is added to the view. You can also add the number column to the view if you want (more of that idea later). It should also be noted that these columns will be added to any bound content types as well.
That’s prepared the content for rating so now go ahead and click some ratings. For my demo I logged in as several users and rated the documents with ratings to demonstrate several of the number of stars.
Timer job
As mentioned earlier the ratings are calculated via a timer job called {user profile SA name} – Social Rating Synchronization Job. This job aggregates the ratings. To speed up the development you can manually execute the timer job to cause the rating aggregation.
Search Managed Properties
So with the native rating functionality function configured and ready for indexing it’s time to swing over to the farm Search Service Application to perform the steps needed to index our ratings.
As with any element within SharePoint content for it to get indexed it needs to be a managed property. By default most common content fields are already configured. Ratings however are not setup in this way. So the first step is to create these managed properties for the ‘Rating (0-5)’ and ‘Number of Ratings’ columns.
AverageRating Managed Property
To create the average rating property map the ‘ows_AverageRating(Decimal)’ as shown in the screenshot below.
Once the properties are configured a index of the content source is required. Browse to the ‘content sources’ and start a crawl. While this is whizzing along in the background the modifications to the search results web part can be made.
Search Results web part
The standard Search Results web part provides the view of the content found matching the query term.
As you can see there are no ratings information displayed. So we’re going to modify the results web part to include the rating and rating count below the content description.
Adding the columns to fetched data
To be able to show the AverageRating and RatingCount results they need to be added to the ‘Fetched Properties"’ xml within the web part settings (the circled element in the screen shot below)
Modify the xml to add the new columns to it. The example below lists the new columns last, you can copy this or append your existing list.
<Columns>
<Column Name="WorkId"/>
<Column Name="Rank"/>
<Column Name="Title"/>
<Column Name="Author"/>
<Column Name="Size"/>
<Column Name="Path"/>
<Column Name="Description"/>
<Column Name="Write"/>
<Column Name="SiteName"/>
<Column Name="CollapsingStatus"/>
<Column Name="HitHighlightedSummary"/>
<Column Name="HitHighlightedProperties"/>
<Column Name="ContentClass"/>
<Column Name="IsDocument"/>
<Column Name="PictureThumbnailURL"/>
<Column Name="PopularSocialTags"/>
<Column Name="PictureWidth"/>
<Column Name="PictureHeight"/>
<Column Name="DatePictureTaken"/>
<Column Name="ServerRedirectedURL"/>
<Column Name="AverageRating"/>
<Column Name="RatingCount"/>
</Columns>
Apply the changes to the web part. Now the data is coming back within the search result set.
Modifying the XSLT
Next step is to get these properties displaying.
I’m not that skilled in front end coding so this will demo the concept and I’m sure those more creative design peeps will add their own flare to the visuals
So I’m choosing to inject the rating and number of raters just after the title and description. Therefore locate the ‘<div class="srch-Metadata2">’ div to inject the new code. Below is a snippet from the section and includes the calls to the new templates.
<div class="srch-Metadata2">
<xsl:call-template name="stars">
<xsl:with-param name="starCount" select="averagerating"/>
</xsl:call-template>
<xsl:call-template name="ratingcount">
<xsl:with-param name="ratingCount" select="ratingcount"/>
</xsl:call-template>
<br/><xsl:call-template name="DisplayAuthors">
<xsl:with-param name="author" select="author" />
</xsl:call-template>…..
As you can see I’ve introduced two new templates, one for each property.
Before we dive into the templates there is something important to share. To improve performance most visual images displayed in css sprite format. This means that css class positions the images to display the required section from a large map of images. The rating control is no different and uses the sprite image found ‘/_layouts/Images/Ratings.png’
So the template to render the stars needs to make use of the same native css classes.
The following is the star rating template. It contains the logic to read the rating value and generate the relevant css positioned rating image.
<!– The Stars displaying –>
<xsl:template name="stars">
<xsl:param name="starCount"/><span class="ms-currentRating">
<!– Set the correct css sprite for the number of stars –>
<xsl:choose>
<xsl:when test="$starCount >= 4.5" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 5 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_5" alt="Current average rating is 5 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 4.5 and $starCount < 5" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 4.5 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_4_5" alt="Current average rating is 4.5 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 4 and $starCount < 4.5" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 4 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_4" alt="Current average rating is 4 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 3.5 and $starCount < 4" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 3.5 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_3_5" alt="Current average rating is 3.5 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 3 and $starCount < 3.5" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 3 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_3" alt="Current average rating is 3 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 2.5 and $starCount < 3" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 2.5 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_2_5" alt="Current average rating is 2.5 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 2 and $starCount < 2.5" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 2 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_2" alt="Current average rating is 2 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 1.5 and $starCount < 2" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 1.5 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_1_5" alt="Current average rating is 1.5 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 1 and $starCount < 1.5" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 1 star.</xsl:text>
</xsl:attribute>
<img class="ms-rating_1" alt="Current average rating is 1 star." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:when test="$starCount >= 0.5 and $starCount < 1" >
<xsl:attribute name="title">
<xsl:text>Current average rating is 0.5 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_0_5" alt="Current average rating is 0.5 stars." src="/_layouts/Images/Ratings.png" />
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="title">
<xsl:text>Current average rating is 0 stars.</xsl:text>
</xsl:attribute>
<img class="ms-rating_0" alt="Current average rating is 0 stars." src="/_layouts/Images/Ratings.png" />
</xsl:otherwise>
</xsl:choose>
</span></xsl:template>
As well as the rating we’re adding the number or people who have rated. This gives the consuming user a decent idea of the level of interest the item has had. The following is the rating count template.
<!– The Rating Count displaying –>
<xsl:template name="ratingcount">
<xsl:param name="ratingCount"/><xsl:choose>
<xsl:when test="$ratingCount = 1" >
<xsl:text>Rated by 1 person.</xsl:text>
</xsl:when>
<xsl:when test="$ratingCount >= 1" >
<xsl:text>Rated by </xsl:text>
<xsl:value-of select="$ratingCount" />
<xsl:text> people.</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>Not rated.</xsl:text>
</xsl:otherwise>
</xsl:choose></xsl:template>
With all these changes applied to the web part settings, save and publish the page and you should find the results now look something like the following screenshot.
Ok so that is pretty cool, users can now see content and peoples ratings of them to assist in finding the right things. It’s not quite the whole story on all the cool things to display, refiners are the other.
Refining by Ratings
With the ratings being displayed in the results it got me thinking that having a refiner for the rating value and number of people who had rated.
So the native refinement web part allows the customisation of the refiners via its settings. One important point to note is that the web part settings will have no effect unless the following check box is unchecked.
The Rating refiner is below.
<Category Title="Rating"
Description="The average rating for the item."
Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"
MetadataThreshold="5"
NumberOfFiltersToDisplay="4"
MaxNumberOfFilters="0"
SortBy="Frequency"
SortDirection="Ascending"
SortByForMoreFilters="Name"
SortDirectionForMoreFilters="Ascending"
ShowMoreLink="True"
MappedProperty="AverageRating"
MoreLinkText="show more"
LessLinkText="show fewer"/>
The Number of Ratings refiner is below.
<Category Title="Number of ratings"
Description="The number of ratings from people for the item."
Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"
MetadataThreshold="5"
NumberOfFiltersToDisplay="4"
MaxNumberOfFilters="0"
SortBy="Frequency"
SortDirection="Ascending"
SortByForMoreFilters="Name"
SortDirectionForMoreFilters="Ascending"
ShowMoreLink="True"
MappedProperty="RatingCount"
MoreLinkText="show more"
LessLinkText="show fewer"/>
Add these to the XML property of the web part.
Save the page and you end up with the refiners for ratings and number of ratings available.
Going the extra step with the refiners
So the initial refiners display any found values. A nice proof of concept would be to add some filter groups to group rating values together into Bronze, Silver, Gold instead of 0-5. That is possible with the refiner property grouping using ranges.
Wrap-up
Hopefully this no-code solution adds some extra sweetness to the use of ratings and search in equal measure.
Great post, well written and clear. Have put this into the knowledgebank… 🙂
Thanks, glad it’s been useful 🙂
Thanks for sharing!
I saw the ratings in the core webpart in some other post – as refiner its great, too.
Nice roundup!
Max
Very nice posting! I love blog posting like this, which can almost directly improve my own solutions 🙂
Thomas
Thanks for the nice post. I was wondering if it is possible to TAG each row of Seach Results?
Hi Manish,
What do you mean by tag each row?? Let me know a little bit more about your idea and I can hopefullu make some suggestions.
Cheers,
Wes
How can I do this search result in decresing order (Highest rated content should display at the first and then lowest and then no rated items). Is this really possible what i am expecting?
Any way to change the ratings in the refinement panel so that it doesnt show 5, 4 , 3 , 2 , 1
one under each other.
Id like to have them either on the same line horizontaly or change the 5 to 5 stars; 4 to 4 stars, etc to make it a bit more visual.
I checked the css but it’s an xsl so it would apply to all, kinda stuck looking for ideas
I’m not sure you can do this with the OOTB web part. You could of course code up a visual refiner web part from scratch and use the object model to get the refiners from the current query.
Wes
Thanks a lot for this post. I definitely will be implementing this first thing tomorrow morning.
I implemnented your solution on a custom list web part and the stars displayed just perfect with the number of people who have rated the list item. However, the stars do not respond on roll-over. Is there a different hack for custom list web parts?
Anticipating your response.
Thanks,
Basil
Hi Basil,
The stars would only respond to roll over if the ‘rating’ functionality is available. The rating in the article is not ‘enabled’ but merely a display of that articles current rating. The reason for not enabling the rating in the search results is a simple one that a user is not likely to have read the content enough to be capable to truely rate it. So not lettting them rate from the results seems sensible.
To implement the functionality in your custom web part i suggest taking a close look at the OOTB implementation. I suspect it’s fired by client side script so should be relatively simple to replicate.
Cheers,
Wes
Hi, Wes!
Nice post. I am having one problem, however: the ows_AverageRating(Decimal) field does not appear when I try to add a managed property. I have rated some pages on my site, and I have run the job you mentioned. Any idea as to what may be causing this?
Thanks!
RP
You need to also make sure you re-crawl (Full Crawl) the search index for that site. When you make a schema change it requires a recrawl to pick the new values up. That should then appear in the list of available properties.
Dear Wes,
Thanks for the post, after doing the steps, I am getting the search results as plain text instead of stars and url’s. checked multiple times but no clue. what could be the reason? please help.
Thanks,
Krishna
Sounds like the most probable cause is a mistake in your XSL markup. Please check that you have a valid XSL.
Thanks Wes for the post, Am getting plain text as search results(with out starts, url etc)checked multiple times but no use. pl help.
I’m getting: “Property doesn’t exist or is used in a manner inconsistent with schema settings.”?