Visualize Your Enterprise Search Results (and Navigation) in SharePoint 2010

A visual representation can be helpful for quickly understanding your search result. We've previously seen how to extend the user experience with a Tag Cloud Web Part, so now let's look at how to leveraging the out-of-the-box refiners to visualize the search results in a SharePoint 2010 search center. We'll walkthrough how to programmatically add a Bar Chart Web Part, a Web Part that will allow us to visualize one dimension of your search results.

Background

Refiners (aka. faceted search) was, as described on the Enterprise Search Blog, previously only available in SharePoint search through 3rd party add-ons. It is now natively supported with SharePoint 2010, and FAST Search adds the ability of "deep" refinement. This is faceted search accross result sets of any size, with precise counts on the refinement values/facets. This is typically critical in certain applications, like e.g. in research and analysis applications where the counts on facets are used for decision making.

In the image below you can see a Bar Chart Web Part added to the left zone in a FAST Search Center. This chart is based on the "format" refiner, and the rest of this blog post will show how to implement such a Web Part. 

 

  

Setup

See my previous post on how to setup your development environment with Visual Studio.

Implementation 

Refinement values can be accessed from the RefinementManager, a class in the Federation OM. To render a nice chart you can use the Chart control, a SharePoint wrapper around the ASP.NET Chart control. With these two components we should be well on our way.

The code below implements a Web Part called BarChartRefinementWebPart (note that the code is for illustration purposes only, not meant to be production ready). The first thing the Web Part does is set up a chart control in the CreateChildControls()  method. This is so we later can add refinement values to it, and render the control. The refinement values we want to chart are fetched in the OnPreRender() method by leveraging the RefinementManager; first an XPath expression is used to select only the refinement values from the "format" refiner (i.e. an out-of-the-box managed property which has a refiner), then the refinement values are added to the chart. Finally, in the Render() method the chart is rendered (unless no refinement values are fetched).

// Copyright © Microsoft Corporation. All Rights Reserved.

// This code released under the terms of the

// Microsoft Public License (MS-PL, https://opensource.org/licenses/ms-pl.html.)

using System;

using System.Drawing;

using System.Web.UI;

using System.Web.UI.DataVisualization.Charting;

using System.Web.UI.WebControls.WebParts;

using System.Xml;

using Microsoft.Office.Server.Search.WebControls;

namespace MyVisualWebPartProject.BarChartRefinementlWebPart

{

    public class BarChartRefinementlWebPart : WebPart

    {

        // the chart for visualizing

        private Microsoft.Office.Server.WebControls.Chart chart;

        // the managed property with a refiner to visualize

       private const string refiner = "format";

        protected override void CreateChildControls()

        {

            // setup the chart

            ChartArea area = new ChartArea("My Chart Area");

            // ..and make it look nice

            area.AxisX.MajorGrid.LineColor = Color.LightGray;

            area.AxisY.MajorGrid.LineColor = Color.LightGray;

               

            chart = new Microsoft.Office.Server.WebControls.Chart();

            chart.Width = 200;

            chart.Height = 200;

            chart.ChartAreas.Add(area);

            chart.EnableViewState = true;

            Controls.Add(chart);

        }

        protected override void OnPreRender(EventArgs e)

        {

            RefinementManager refinementManager = RefinementManager.GetInstance(this.Page);

            // get the refinement values

            XmlDocument refinementXmlDoc = refinementManager.GetRefinementXml();

            if (refinementXmlDoc != null)

            {

             // collect refinement values to chart

                Series refinementSeries = new Series();

                refinementSeries.ChartType = SeriesChartType.Bar;

                refinementSeries.Color = Color.LightSkyBlue;

                refinementSeries.BorderColor = Color.LightGray;

                XmlNodeList xmlFilterNodes = refinementXmlDoc.DocumentElement.SelectNodes("/FilterPanel/FilterCategory[@ManagedProperty='" + refiner + "']/Filters/Filter[Count>0]");

                foreach (XmlNode filter in xmlFilterNodes)

                {

                    string x = filter.SelectSingleNode("Value").InnerText;

                    string y = filter.SelectSingleNode("Count").InnerText;

                    int i = refinementSeries.Points.AddXY(x, y);

                    // display count in chart

                    refinementSeries.Points[i].Label = y;

                    // ..and make chart clickable

                    refinementSeries.Points[i].Url = filter.SelectSingleNode("Url").InnerText;

      }

                if (refinementSeries.Points.Count > 0)

                    chart.Series.Add(refinementSeries);

            }

        }

        protected override void Render(HtmlTextWriter writer)

        {

            if (chart.Series.Count == 0)

            {

                writer.Write("<p><center>No data to render for property " + refiner + "</center></p>");

            }

            else

            {

                base.Render(writer);

            }

        }

    }

}

 

We are dependent on refinement values being available for this Web Part to work. In the out-of-the-box search center in SharePoint, the set of refiners to fetch is set in the Refinement Panel Web Part. So as long as this Web Part is also part of your page or search center, we can leverage this. Note that the RefinementManager is shared on a page, similar to the SharedQueryManager we used for the Tag Cloud. If we cannot assume that the RefinementWebPart will be available, we can set which refiners to fetch ourselves. Alternatively we can extend the RefinementWebPart class.

Summary

This blog post has shown how to leverage an out-of-the-box refiner in SharePoint 2010 to visualize your search results. The RefinementManager in the Federation OM provides a place to hook in so you easily can create new Web Parts that will work nicely with other search Web Parts. It is the same interface for both FAST Search and SharePoint Search, but with FAST Search you get "deep" refinements, i.e. faceted search across the entire result set.