Pages

Showing posts with label SharePoint 2010. Show all posts
Showing posts with label SharePoint 2010. Show all posts

Thursday, August 22, 2013

Keyword Query in SharePoint 2013


With the release of SharePoint 2013, a lot has changed with the way things were being implemented. For instance, till SP 2010, it was possible to use FullTextSQLQuery to query the results obtained from SharePoint Search Crawls. It was much easier to use considering its syntax was similar to SQL.

Now, in SP 2013, it has been deprecated. There is not even a provision to support backward compatibility FullTextSQLQuery on SharePoint 2013 platform. The only place we developers can now resort to is the KeywordQuery. It can be implemented in the pretty much same way as it was implemented on SP 2010.

So, let me take this opportunity to shed some light on Keyword Query and how it can be used to query crawl results.

KeywordQuery supports two syntax for query string formation –
  1. Keyword Query Language (KQL) and
  2. FAST Query Language (FQL)

KQL is the default syntax which can be used. FQL needs to be explicitly enabled to use it. Following is the sample code which showcases both these approaches –

Approach 1 – KeywordQuery using KQL

static void Main(string[] args)
{
SPSite site = new SPSite("url_whose_results_you_wish_to_query");
SearchServiceApplicationProxy proxy = (SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(SPServiceContext.GetContext(site));

using (KeywordQuery keywordQuery = new KeywordQuery(proxy))
   {
    keywordQuery.ResultsProvider = SearchProvider.Default;
    keywordQuery.StartRow = 0;
    keywordQuery.RowLimit = 500;
    keywordQuery.EnableStemming = true;
    keywordQuery.TrimDuplicates = false;
    keywordQuery.AuthenticationType = QueryAuthenticationType.PluggableAuthenticatedQuery;
    keywordQuery.Culture = CultureInfo.CurrentCulture;
    keywordQuery.KeywordInclusion = KeywordInclusion.AllKeywords;
    keywordQuery.QueryText = "scope:\"All Sites\" AND (contentclass:\"STS_Site\" OR contentclass:\"STS_Web\")";
    keywordQuery.SelectProperties.Add("path");
    keywordQuery.SelectProperties.Add("title");
    keywordQuery.SelectProperties.Add("contentclass");
    SearchExecutor executor = new SearchExecutor();
    ResultTableCollection resultTableCollection = executor.ExecuteQuery(keywordQuery);
    var resultTables = resultTableCollection.Filter("TableType", KnownTableTypes.RelevantResults);
    var resultTable = resultTables.FirstOrDefault();
    }
}


In the above code snippet, note the SPSite URL which should be URL of the site whose search results you wish to query.

In the previous version of SharePoint, RowLimit actually had no limits. But in newer versions, it has the maximum limit of 500. This number is however configurable if we run PowerShell script on the SharePoint Search Service Application.

Also, note that now, we cannot directly execute the Query. Earlier we would simply call the method

KeywordQuery.ExecuteQuery()

and it would fetch the results for us. Now, SP 2013 introduces a new class SearchExecutor specifically built to execute queries. So in order to run a query, we would first have to initialize this class and then call its ExecuteQuery method on our KeywordQuery.

ResultType class and its corresponding KeywordQuery.ResultType property are also now obsolete. Instead we would now need to call a filter method on our resultant collection to get our desired results (see the code above).

Notice the query text in the above snippet. It is much similar to what was used in SP 2010.

Another important thing to notice above is that we would need to explicitly specify which columns should be returned in the query result. Of course, it was done earlier and in much simpler fashion using FullTextSQLQuery. Now, we would need to call the method –

keywordQuery.SelectProperties.Add("<column_name>")

to return this column in the result table collection.


Approach 2 – KeywordQuery using FQL
  
static void Main(string[] args)
{
    SPSite site = new SPSite("<url_whose_results_you_wish_to_query>");
    SearchServiceApplicationProxy proxy = (SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(SPServiceContext.GetContext(site));
    using (KeywordQuery keywordQuery = new KeywordQuery(proxy))
    {
        keywordQuery.ResultsProvider = SearchProvider.Default;
        keywordQuery.SourceId = new Guid("<RESULT_SOURCE_GUID>");
        keywordQuery.EnableFQL = true;
        keywordQuery.StartRow = 0;
        keywordQuery.RowLimit = 500;
        keywordQuery.EnableStemming = true;
        keywordQuery.TrimDuplicates = false;
        keywordQuery.AuthenticationType = QueryAuthenticationType.PluggableAuthenticatedQuery;
        keywordQuery.Culture = CultureInfo.CurrentCulture;
        keywordQuery.KeywordInclusion = KeywordInclusion.AllKeywords;
        keywordQuery.QueryText = "and(scope:string(\"All Sites\"), or(contentclass:string(\"STS_Site\") , contentclass:string(\"STS_Web\")))";
        keywordQuery.QueryText = "and(scope:string(\"All Sites\"), or(contentclass:STS_Site, contentclass:STS_Web))";
        keywordQuery.SelectProperties.Add("path");
        keywordQuery.SelectProperties.Add("title");
        keywordQuery.SelectProperties.Add("contentclass");
        SearchExecutor executor = new SearchExecutor();
        ResultTableCollection resultTableCollection = executor.ExecuteQuery(keywordQuery);
        var resultTables = resultTableCollection.Filter("TableType", KnownTableTypes.RelevantResults);
        var resultTable = resultTables.FirstOrDefault();
    }
}


Notice the highlighted lines of code in Cyan color in the above snippet. Only those lines are different from what we saw earlier. Rest all settings remain the same. in the above example, i have used two types of FQL queries. You can use either of them.

SourceID needs to be explicitly mentioned here because in SharePoint 2013, we need to create a custom Result Source which possesses a different query string in it. I would cover creating Result Sources in SharePoint 2013 in a separate post.


Happy coding !!

Monday, August 19, 2013

Accessing SharePoint User Profiles using PowerShell commands


This post will help you access the user profiles stored within your User Profile Service Application. It is applicable to both SharePoint 2010 as well SharePoint 2013.

Load the SharePoint snap-in into your management shell -

$snapinName = "Microsoft.SharePoint.PowerShell"
if ((Get-PSSnapin | Where-Object {$_.Name -eq $snapinName }) -eq $NULL)
{
  write-host "SharePoint SnapIn not loaded. Loading..."
  Add-PSSnapin $snapinName -ErrorAction SilentlyContinue
}

Create the SPService Context used to initialize the Profile Manager instance -

$proxyGroup = Get-SPServiceApplicationProxyGroup -default
$subId = [Microsoft.SharePoint.SPSiteSubscriptionIdentifier]::Default
$context = [Microsoft.SharePoint.SPServiceContext]::GetContext($proxyGroup, $subId)

Initialize the ProfileManager object using the created Context object -

$ProfileManager = new-object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)

Using this object, create an Enum type object to iterate / enumerate through all the user profiles -

$Profiles = $ProfileManager.GetEnumerator()

Now, there are two ways to loop through these profiles -

1. Using foreach loop

foreach($profile in $Profiles)
{
$property1 = $profile["<Property_Name>"].Value
$property2 = $profile["<Property_Name>"].Value
}

Above, <Property_Name> denotes the name of any user profile property you have created or is available out-of-the-box.

2. Using while loop

while($Profiles.MoveNext())
{
$profile = $Profiles.Current
                $property1 = $profile["<Property_Name>"].Value
$property2 = $profile["<Property_Name>"].Value
}


If you wish to save or export the profile data into a CSV file, you can modify your code above to something like below -

Using foreach loop approach -

Get the location of the file which should save your data -

$propertiesFileName = "\UPA-Profiles.csv"
$outputFile = (Get-Location -PSProvider FileSystem).ProviderPath + $propertiesFileName

Create a Collection which would every single row of your CSV file -

$collection = @()

Then, the loop -

foreach($profile in $Profiles)
{
$profileData = "" | select "Property1","Property2","Property3"
$profileData.Property1= $profile["<Property_Name>"].Value
$profileData.Property2= $profile["<Property_Name>"].Value
$profileData.Property3= $profile["<Property_Name>"].Value
$collection += $profileData
}
$collection | Export-Csv $outputFile -NoTypeInformation


Hope this helps ...