Custom Processing Pipeline Stage to Manipulate Managed Properties in SP2013 Search

July 22, 2013 Leave a comment

Synopsis: In this post i write about a way to inject values before the content gets indexed in SharePoint 2013.

Though this process is called to be as “Custom Processing Pipeline Stage in Fast Search” it is no more referred that way, so is its Architecture today.

It is referred to as

” Content Enrichment Call Out Web Service”

What is this step for during Crawling or before Indexing content?

Either be it Fast ESP or SP2013 ( albeit their architecure is different for this step), this stage/step helps to manupilate the exisitng managed property value or inject a new value into a new Managed Field ( ideally which the crawler cannot do).

Any Business Scenario?

Yes, lets say content is being extracted from a Database. The current search engines has the ability to map the columns ( Cralwed Properties) to Managed Properties. There by the managed properties can be used to refine the data. Clear?

Now lets say that the Database contains data about a company’s world wide business. There is one field in the table which is not very important to the business the “Description”. The Description always has the text

 ” We also have Accomodation for employees in the city London”

Lets asssume that the pattern of this text is going to be common. The content which changes from record to record is the city name from this field.

The todays search engine can map the Description field to a Managed Property, but cannot extract the City Name from it and map to a new managed property.

That is where this new stage/step helps.

The custom stage we write can have the logic to break a pattern, extract the terms and assign the new managed properties the terms we extracted.

There by the business has the advantage to refine the results by the location where the employees can avail accomodation.

How to do it SP2013?

Earlier in Fast ESP we need to modify the PipelineConfig.xml, point our custom stage as an exe or a powershell script.

In SP2013, a WCF service hosts the logic. Which takes the input as a set of Managed Property(s) and returns a set of Managed Property(s).

The service architecture helps in reducing the load on the server. However reduces the crawl rate.

Logic to be written in a Web Service:

 

ProcessedItem processedItem = new ProcessedItem();

            try            {

                foreach (var property in item.ItemProperties)
                {
                    // Check if this is the author property.
                    if (property.Name.Equals(“Description”, StringComparison.Ordinal))
                    {
                        var desc = property as Property<List<string>>;
                        description = desc.Value[0];
                        break;
                    }
                }
                processedItem.ItemProperties = new List<AbstractProperty>();
                Property<string> modelProp = new Property<string>()
                {
                    Name = “Location”,
                    Value = “Extract Content from Description”
                };
              
                processedItem.ItemProperties.Add(modelProp);
               
              
            }
Once the service is hosted on any server , this needs to be registered to the Search Service Application using powershell.
As below.
$ssa = Get-SPEnterpriseSearchServiceApplication
$config = New-SPEnterpriseSearchContentEnrichmentConfiguration
$config.Endpoint = http://Site_URL/ContentEnrichmentService.svc
$config.InputProperties = "Description"
$config.OutputProperties = "Location"
Set-SPEnterpriseSearchContentEnrichmentConfiguration –SearchApplication
$ssa –ContentEnrichmentConfiguration $config

For a brief example refer Technet Article :http://msdn.microsoft.com/en-us/library/jj163968.aspx

Thanks,

Sreeharsha​

Know your search Topology – SP2013

$ssa = Get-SPEnterpriseSearchServiceApplication
$active = Get-SPEnterpriseSearchTopology -SearchApplication $ssa -Active
Get-SPEnterpriseSearchComponent -SearchTopology $active

BCS Attachment Accessor – Search SQL Related Tables

June 17, 2013 Leave a comment

Hello folks,

I have been working on Business Connectivity Services with SQL tables since a while. And there has been a requirement, where Three Tables are linked through a primary key – foreign key relationship. These tables are to be searchable. But the specific requirement here is that when searched for content in the child tables, the parent item related to it should be displayed on the search result page instead of the child table parent entity.

I questioned my client why would you want to do that way. He replied ” Consider the child tables are paragraphs in a document, when searched for content within it, i should be able to see the link to the document , but need not be each paragraph”. Which makes sense to me. After a little search, mails could figure out that this is very much possible and can be achieved through “Associations as Attachments”.

So here is how we did it.

As i said there are three tables. Table 1 (Cars) , Table 2 ( Parts) Table 3 (Issues)

Here, as per the SQL Table 1 is directly linked to Table 2. Table 2 is linked to Table 3. But there is no direct association between Table 1 and Table 3.

BCS Association is implemented between Table 1 and Table 2, a Custom implementation.

To ensure, that Table 1 Item be displayed on the search results when searched for Content within Table 3, a Foriegn-key less association is made. By saying that, i mean i have implemented a custom stored procedure to read the content from Table 3 which are linked to Table 1 through Table 2. Using Joins.

Now to ensure that, the association acts to make the child table as an attachment , here is what need to be added in the method instance of the association.

<MethodInstances>
<Association Name=”PartItemToRevisionItem” Type=”AssociationNavigator” ReturnParameterName=”revisionAssociationItemList” IsCached=”false”>
<Properties>
<Property Name=”AttachmentAccessor” Type=”System.String”></Property>
</Properties>
<SourceEntity Name=”PartItem” Namespace=”MultiBCS.MultiEntity” />
<DestinationEntity Name=”RevisionItem” Namespace=”MultiBCS.MultiEntity” />
</Association>
</MethodInstances>

This specific tag ensures that the child item be crawled as an attachment.

I will be writing a complete post on creating a BCS Association for search sooner.

I Thank Joseph who is my lead who have given me enough opportunity to research and execute , Scot Hilier a MVP an expert on BCS who gave the right pointer to start with.

Thank you. Happy coding .

Easy Zone Tabs

September 2, 2012 Leave a comment

Hello Folks,

In this post I will write an idea on implementing the feature called "Easy Zone Tabs” through a Visual Web Part.

Here is the basic idea/requirement for this functionality.

1. A Tabbed Web Part has to be built within which several Web Parts has to be grouped.

2. Users should be able to toggle within the Tabs to see multiple Web Parts within the same Zone without a Page Refresh for on Tab Click Event.

So here is how it is implemented.

1. A Visual Web Part collects the information from the User from a Custom Tool Pane on the Number of Tabs, which web parts to be displayed and which to be hidden.

2.  With the Information in hand , on page load / Or on Click of the Tabs the respective selected Web Parts will be shown/hidden.

Here is how the Web Part has to be Configured to see the explained functionality. Refer the Picture below.

Basic

 

WebPart Settings

Once the settings are saved , this is how the Web Part works. Refer the image below.

Tabs

 

 

Technical Implementation:

 

Lets dig in a level deep and understand how this is done.

There are three parts of development in this Web Part. 1. Tool Pane Development to collect information from the User.

2. Data Source (XML ) which need to be queried

Get the Tabs where this Web Part is enabled.

Get the Web Parts enabled for this Tab.

3. Web Part UI – To handle Page Load, Tab Click events using JQuery/Java Script.

In the first part of the development on the Page load of the custom tool page, the Web Parts that are a part of the Current Zone are read using the SPLimitedWebpartManager class.

There will be a maximum number of Text Boxes that will be allowed for the user to enter the Names of the Tabs.

Each Text Box can represent a Tab and Multiple Web Parts can be selected under each Tab.

When the user provides the name of the Tab and clicks refresh, the Check Boxes will be enabled against the Web Parts.

The chosen Web Parts’ ID are selected and stored in an XML which is saved in a string format.

 

When the user finally saves the Web Part, the information that needs to be stored are – All the Web Parts’ ID in the Current Zone except the easy Zone Tabs Web Part and the XML that maps the Tabs vs Web Parts’ ID.

This is how the data is stored in an XML file. But this format can be changed anyways. I found this format easy to query using LINQ.

TabsXML

 

On return of the Page Load of the Custom Tool Pane, the Check Boxes need to be checked based on the selection the User has made earlier.

 

Now once these settings were saved in a serialized object, on page load of the user control the system should read the values on what Web Parts to be visible and what Web parts to be hidden based on the XML that is stored.

Each Web Part node contains the information of the Web  Part ID and the Tabs on which it is enabled. Usinq LINQ these IDs were extracted and stored in label. ( There are 6 such labels. hidden on the page).

 

Using JQuery based on the Tab clicked(First Tab in case of Page Load), get the parent Element in the Page Source HTML where the Web Part ID is found and Set the Display as None.

var cut = allwps[i].toString();
var cutt = cut.replace(/_/g, "-");
//alert(cutt);
var current = $("div[WebpartID=" + cutt + "]");
//alert($(current).parent());
// if (current == null) {
var current1 = $("div[WebpartID2=" + cutt + "]");
// }
$(current).parent().parent().parent().parent().parent().hide();
$(current1).parent().parent().parent().parent().parent().hide();

A Point to mention here is that the Web Part ID read from the Code can be found on the Page Source HTML against the Variable WebpartID if the Web Part is a Custom Web Part and against WebpartID2 if the Web Part is a OOB Web Part. hence both the conditions are verified.

 

Hope this implementation gives an Idea on how to implement a Zone Tab Web Part that lets the user choose the Web Parts , Hide or Show without a Page Refresh.

The code/solution is available for download here

How to Create the Objects of SPSite and SPWeb while developing WebParts, Event Handlers, TimerJobs, Workflows.

August 25, 2012 Leave a comment

 

While developing Web Parts

The Objects of SharePoint like SPSite, SPWeb can be created using the Context.

SPSite site=SPContext.Current.Site.

SPWeb web=SPContext.Current.Web.

These objects need not be disposed explicitly because they are a part of the Current Context.

Creating the objects with the context of the user will allow the user to read the objects or data based on the user’s permissions.

The necessity of creating an Object of SPSite or SPWeb like below, comes into picture when there is a need to access any objects or data which is a part of the other site collection or when data has to be read on elevated privileges.

 

These objects have to be disposed explicitly, if Using (){} statement is not used.

Using(SPSite site=new SPSite(url))

{

using(SPWeb web=site.OpenWeb()

{

}

}

 

Running the Code under elevated Privileges.

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using(SPSite site=new SPSite(url)

{

using(SPWeb web=site.OpenWeb()

{

}

}

});

 

When RunWithElevatedPrivileges is used, the objects of Site and Web have to be created, rather  than using the current context objects. Otherwise, the items, data, objects will be not be retrieved with elevated privileges but with the current user’s authority.

 

While Developing Timer Jobs.

Timer Jobs will be handled by OWSTimer Service at a Web Application level. SPSite and SPWeb doesn’t exist at this level.

A way to access a Site Object is to iterate through the Site Collections of theWebapplication.

foreach (SPSite siteCollection in this.WebApplication.Sites) {
    //Your Site                                                             }

 

While developing Event Handlers

public override void ItemAdded(SPItemEventProperties properties)

       {

           base.ItemAdded(properties);

           SPSite site = properties.OpenSite();

           SPWeb web = properties.OpenWeb();

       }

These objects are retrieved from the Properties of the current event handler. They need not be disposed.

While Developing Workflows

SPSite site=workflowProperties.Site;
SPWeb web = workflowProperties.Web;

These objects need not be disposed.

Categories: How to SP

How to READ items from Sharepoint List through a Visual Webpart

August 25, 2012 Leave a comment

Here I am with the first post in this series.

Though there are many ways to read the items from a list it varies depending on what kind of WebPart we are going to develop.

In this post i shall post the code that helps in reading the items from the list using a View.

The reason why a view is used to frame CAML query is that the query can be changed any time. The sort order, filter criteria  and number of items can he specified through UI(View Settings) . So no need to touch the code anytime later.

Here you go.

public static SPListItemCollection GetListItems(string siteUrl, string webServerRelativeUrl, string listName, string viewName)
{
SPListItemCollection itemColl = null;
using (SPSite site = new SPSite(siteUrl))
{
using (SPWeb web = site.OpenWeb(webServerRelativeUrl))
{
SPList list = web.Lists.TryGetList(listName);

if(list!=null)
{
SPView view = list.Views[viewName];
if(view==null)
{
view = list.DefaultView;

                       }
SPQuery query = new SPQuery();
query.Query = view.Query;
query.RowLimit = view.RowLimit;
itemColl = list.GetItems(query);

                        }
}
}
}
return itemColl;
}

Happy Coding Smile

Categories: How to SP

Custom My Site Social Buttons – I Like It, Tags and Notes

April 13, 2012 2 comments

Hello Folks,

Ever thought of creating custom image buttons that implements the functionality of I Like It , Tags and Notes on SharePoint 2010?

Came across a requirement where the images used for these have to be custom. I thought of replacing the Social tagging, Social Notes images from the Images folder.

 

 

But SharePoint implements this through a delegate control.These delegate controls are referred though a user control called SocialData.ascx from the control templates.

Confused with all these files and the way they are linked, i have to rethink my requriements.

1. I like it , Tags and Notes funtionality need to be implemented.

2. They need to use custom images.

The OOB controls refer the class Microsoft.Sharepoint.Portal.WebControls.SocialNotificationControl and Microsoft.Sharepoint.Portal.WebControls.SocialNotificationBase.

The image that is referred OOB is the Image Map which is a combination of many images. So cant replace the image from the Images folder.–>  “/_layouts/images/mossfgimg.png”

 

 

Using the Reflector i could understand that these controls simply call the methods from the SocialData.js.

Here is how a custom I Like it button can be implemented on Any Page.

<script type=”text\ecmascript”>

function AddCompanyQuickTag() {
SafeRunFunction(function () {
var o = new SocialQuickTag(“ClientID”);
o.url = document.URL;
o.title = document.title;
o.tagged_text =’Tagged the page as I Like It’;//The text can be changed. This will be displayed as a notification when I like it button is clicked and the page is tagged.
o.AddQuickTag(0);
}, ‘SocialData.js’, ‘SocialQuickTag’);
}

</script>

<div>

<a onclick=”AddCompanyQuickTag()”><img src=”/_layouts/images/heart_icon.png”></a>

</div>

And here is how you can implement a custom Tags and Notes feature on any page.

<script type=”text\ecmascript”>

function GetINFATagsForThePage() {

SafeRunFunction(function () {
var o = new SocialTagsAndNotes(‘getTags101’);
o.url = document.URL;
o.GetSocialNotification();}, ‘SocialData.js’, ‘SocialTagsAndNotes’);
}

</script>

<div>

<a title=”Tags help you remember links and classify the page. Notes are public comments. Tags and notes post to your news feed and work across different sites.” id=”getTags101″  onclick=”SafeRunFunction(function() { TagDialogOpener.Open(document.url, document.title, ‘0’); }, ‘SocialData.js’, ‘TagDialogOpener’);” onmouseover=”GetTagsForThePage()”><img src=”/_layouts/images/message_icon.png”></a>
</div>
PS: OnMouseOver of theTags and Notes, the title will be appened with the total number of tags the page has. This is OOB functionality and can be understood from the methods(SocialTagsAndNotes) in the SocialData.js from Layouts folder. But for some strange reasons i couldnt see that on my page. If anyone could know the reason would be of a great help.
Happy coding🙂
Follow

Get every new post delivered to your Inbox.