Using the KeywordQuery class to search SharePoint content

Using the KeywordQuery class to search SharePoint content

You can use the KeywordQuery class to search SharePoint content using a search query string formatted in the same way you would if you used the Search Center user interface. This makes it really easy to structure (and test) search queries for use in your applications.

In this example, I have a SharePoint list that has a little over 300,000 items in it. The items are of ships moving in and out of a shipping port. My example webpart is going to allow a user to enter the flag of country and date range. Using these inputs, it will search the data in SharePoint and return a DataTable of results, from all lists with a specific content type (the shipping data), within the time period and with the specified flag. Finally, the data will be presented in a chart.

Note: For more information on using charts in webparts, see SharePoint 2010: Adding Charts to Standard Webparts and Visual Webparts

1. To get started, open Visual Studio and create a new Farm based Empty SharePoint solution
2. Add a project reference to Microsoft.Office.Server.Search, and System.Web.DataVisualization, then add the required using statements
using System.Web.UI.WebControls.WebParts;
using Microsoft.Office.Server.Search.Administration;
using Microsoft.Office.Server.Search.Query;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using SortDirection = Microsoft.Office.Server.Search.Query.SortDirection;
using System.Web.UI.DataVisualization.Charting;

3. Add a new Standard Webpart to the page, giving it the name VesselMovement
4. Add controls to the class for selecting a date range, entering a flag, updating results and displaying the details in a chart.
private Button _update;
private Chart _chart;
private TextBox _flag;
private DateTimeControl _fromDate;
private DateTimeControl _toDate;

5. Initialise the controls in the OnInit method, then add them to the page in the CreateChildControls method
protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    _update = new Button() { Text = "Update" };
    _update.Click += UpdateOnClick;
    _chart = new Chart();
    _flag = new TextBox();
    _fromDate = new DateTimeControl();
    _fromDate.SelectedDate = DateTime.Now.AddMonths(-1);
    _fromDate.DateOnly = true;
    _toDate = new DateTimeControl();
    _toDate.SelectedDate = DateTime.Now;
    _toDate.DateOnly = true;
}
 
protected override void CreateChildControls()
{
    Controls.Add(new LiteralControl("<table style=\"width:400px;border:0;\">"));
    Controls.Add(new LiteralControl("<tr><td><span>From</span>"));
    Controls.Add(new LiteralControl("</td><td colspan=\"2\">"));
    Controls.Add(_fromDate);
    Controls.Add(new LiteralControl("</td></tr><tr><td><span>To:</span></td><td colspan=\"2\">"));
    Controls.Add(_toDate);
    Controls.Add(new LiteralControl("</td></tr><tr><td><span>Flag</span></td><td>"));
    Controls.Add(_flag);
    Controls.Add(new LiteralControl("</td><td>"));
    Controls.Add(_update);
    Controls.Add(new LiteralControl("</td></tr></table>"));
    Controls.Add(new LiteralControl("<div style=\"margin-top:5px;\">"));
    Controls.Add(_chart);
    Controls.Add(new LiteralControl("</div>"));
}

6. Create a new method, called GetVesselData, that will use the KeywordQuery class to perform a search using SharePoint's search engine. This method will return a DataTable containing the search results.
private DataTable GetVesselData(String flag, String dateRangeFrom, String dateRangeTo)
{
    try
    {
        var ssaProxy = (SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(SPServiceContext.GetContext(SPContext.Current.Site));
        var keywordQuery = new KeywordQuery(ssaProxy);
        keywordQuery.RowLimit = 100;
        keywordQuery.SelectProperties.Clear();
        //Add properties to return
        keywordQuery.SelectProperties.Add("Title");
        keywordQuery.SelectProperties.Add("PrimaryDate");
        //trim duplicates
        keywordQuery.TrimDuplicates = true;
        //Sort the results on a custom field, PrimaryDate (Mangaged Property)
        keywordQuery.SortList.Add("PrimaryDate", SortDirection.Descending);
        keywordQuery.ResultsProvider = SearchProvider.Default;
        keywordQuery.ResultTypes |= ResultType.RelevantResults;
        //Create the search query
        keywordQuery.QueryText = String.Format("FLAG:\"{0}\" AND contenttype:SMARShipMovement AND (PRIMARYDATE>{1} AND PRIMARYDATE<{2})", flag, dateRangeFrom, dateRangeTo);
        ResultTableCollection searchResults;
        try
        {
            searchResults = keywordQuery.Execute();
        }
        catch (Exception)
        {
            //"Your query is malformed. Please rephrase your query."
            return new DataTable();
        }
        if (searchResults.Exists(ResultType.RelevantResults))
        {
            var searchResult = searchResults[ResultType.RelevantResults];
            var results = new DataTable { TableName = "SearchResults"};
            results.Load(searchResult, LoadOption.OverwriteChanges);
            return results;
        }
    }
    catch (Exception e)
    {
        //Unhandled Exception running query
    }
    return new DataTable();
}

7. Using the datatable, we can now display the results in a number of ways. One way would be to display the data in an SPGridView. In this example though, we are going to display the data in a chart.  To do this, we'll pass the datatable to another method, that will group and count the data, then display it in a chart.
private void PopulateChart(DataTable dataTable)
{
    try
    {
        _chart.Width = 315;
        _chart.Height = 350;
        _chart.AntiAliasing = AntiAliasingStyles.All;
        _chart.TextAntiAliasingQuality = TextAntiAliasingQuality.High;
        Series s = PlotVesselActivity(dataTable);
        ChartArea ca = ChartArea();
        _chart.ChartAreas.Add(ca);
        _chart.Series.Add(s);
        _chart.Visible = true;
    }
    catch
    {
        _chart.Visible = false;
    }
}
 
private static ChartArea ChartArea()
{
    ChartArea chartArea = new ChartArea();
    chartArea.BackColor = Color.Gray;
    chartArea.BackSecondaryColor = Color.DarkGray;
    chartArea.BackGradientStyle = GradientStyle.TopBottom;
    chartArea.AxisY.Title = "Times In Port";
    chartArea.AxisY.IsStartedFromZero = false;
    chartArea.AxisX.Title = "Vessel";
    chartArea.AxisX.Interval = 1;
    return chartArea;
}
 
private Series PlotVesselActivity(DataTable dataTable)
{
    var series = new Series();
    series.Color = Color.ForestGreen;
    series.BackSecondaryColor = Color.GreenYellow;
    series.BorderColor = Color.Firebrick;
    series.BackGradientStyle = GradientStyle.TopBottom;
 
    var dv = new DataView(dataTable);
    var groupedData = dv.ToTable(true, new[] { "Title" });
    groupedData.Columns.Add("Count", typeof(int));
    foreach (DataRow row in groupedData.Rows)
    {
        row["Count"] = dataTable.Compute("Count(Title)", "Title = '" + row["Title"] + "'");
    }
    var xpoint = 0;
    foreach (DataRow r in groupedData.Rows)
    {
        var p = new DataPoint
        {
            XValue = xpoint,
            YValues = new double[] { Convert.ToDouble(r["Count"].ToString()) },
            Name = r["Title"].ToString(),
            AxisLabel = r["Title"].ToString()
        };
        xpoint++;
        series.Points.Add(p);
    }
    return series;
}

8. Finally, add code for the Update button OnClick event. The OnClick event will pass the selected flag and date range through to the GetVesselData method
private void UpdateOnClick(object sender, EventArgs eventArgs)
{
    if (Page.IsPostBack)
    {
        var results = GetVesselData(_flag.Text, _fromDate.SelectedDate.ToShortDateString(), _toDate.SelectedDate.ToShortDateString());
        PopulateChart(results);
    }
}


The finished results looks like this:


People asked questions about SharePoint Search in these forums questions:

http://social.technet.microsoft.com/Forums/sharepoint/en-US/15c9f903-ffa2-4ac5-8302-e0845bb414c9/sharepoint-foundation-document-search-web-part
http://social.technet.microsoft.com/Forums/sharepoint/en-US/7edd70ba-c64b-43f7-b252-65ad766d2132/sharepoint-search-fulltextsqlquery

Leave a Comment
  • Please add 4 and 1 and type the answer here:
  • Post
Wiki - Revision Comment List(Revision Comment)
Sort by: Published Date | Most Recent | Most Useful
Comments
  • Matthew Yarlett edited Revision 1. Comment: Added a link to another forum question (in June) about SharePoint Search

  • Matthew Yarlett edited Original. Comment: Fixed a link

Page 1 of 1 (2 items)
Wikis - Comment List
Sort by: Published Date | Most Recent | Most Useful
Posting comments is temporarily disabled until 10:00am PST on Saturday, December 14th. Thank you for your patience.
Comments
  • Matthew Yarlett edited Original. Comment: Fixed a link

  • Matthew Yarlett edited Revision 1. Comment: Added a link to another forum question (in June) about SharePoint Search

Page 1 of 1 (2 items)