Friday, October 31, 2014

Caution: If you have scripted your Search Service Application (eg. AutoSPInstaller) in SharePoint 2013 your search based pages could end up like this

Important!
If you have scripted your SSA, make sure the farm account has db_owner on your search db’s, or you may find yourself in a lot of trouble one day!

search-based-intranet

Wednesday, October 29, 2014

Retrieve Search Center URL from a SharePoint page

I have previously written about how you via REST can retrieve the Search Center URL for a particular SharePoint site.

If you are already on a page which has a search web part on it, you can get the same value from the page itself with the following command:

Srch.ScriptApplicationManager.get_current().states['searchCenterUrl']


To be clear; when a search web part exist on the page search Search.ClientControls.js is loaded and makes the Srch namespace available.

Tuesday, October 28, 2014

How to change the number of decimal places on a number column using CSOM

Got a challenge for a one liner by the strongest man in SharePoint (@tarjeieo) to do this using CSOM as with with SSOM you can set the DisplayFormat property of the field. Using CSOM, this property is not available.

A one liner would be ugly, but the way to accomplish this is to modify the SchemaXml of the field, so you could encapsulate the code below in a function.

Using XML manipulation I ended up with this.

ClientContext clientContext = new ClientContext("https://site/);
Web web = clientContext.Web;
Field field = web.Fields.GetByTitle("DummyNum"); // Field to modify
clientContext.Load(field);
clientContext.ExecuteQuery();
XmlDocument doc = new XmlDocument();
doc.LoadXml(field.SchemaXml);
XmlNode fieldNode = doc.SelectSingleNode("Field");
XmlAttribute decimalAttribute = fieldNode.Attributes["Decimals"];
if (decimalAttribute == null)
{
decimalAttribute = doc.CreateAttribute("Decimals");
fieldNode.Attributes.Append(decimalAttribute);
}
decimalAttribute.Value = "4";
field.SchemaXml = doc.OuterXml;
field.UpdateAndPushChanges(true);
clientContext.ExecuteQuery();

Monday, October 27, 2014

Caution when creating global query rules

If you create query rules which modify the query on your tenant or SSA level, then you are effectively killing off any such rules on the site collection level.

The below screen shot is taken running a query in the query rule tester. You see the first rule for blog’s is triggered. This rule has been set to stop, as it modifies the query and I want no more processing. You can see the stop flag actually works works, as the next rule is grayed out.

But then a rule from the SSA is showing in blue again, not honoring the Stop flag from the site collection. Ideally it should have been grayed out as well. The reason for this is that if you have more than one rule which modifies your query, then neither is executed (even though the test interface shows so).

image

In my case the SSA rule is adding an exclusion rule for all search results on Local SharePoint Results. The way to solve this is to create a custom result source on the SSA (or any other level where you need it), add the exclude filter here, and set this source as the default source instead.

Or if the results excluded shouldn’t be used anywhere, mark the site not to be indexed instead.

Tuesday, October 21, 2014

I'm doing an extra talk at SharePoint Connect 2014 - Social Refiners is the game!

Back in May I posted about SharePoint Connect 2014 letting me in to do a talk about Search Queries Explained. A vacant spot just opened up and I was asked if I could do one more, and I jumped at the chance.

I've decided to do a developer talk on how to create "Social" refiners on your search result pages.

The session will involve Display Templates and JavaScript with some FQL sprinkled in. I will show how to create my trusty old Department refiner for content and a refiner for content close to you, both based on your organization, who you follow and who you interact with from the Office Graph.

Hopefully you will pick up a trick or two and get some ideas for your next project - and if you are near sighted, sit up front as it's all code :)

Monday, October 20, 2014

Look up item based on the Item’s ID

If you kick off a search query you get some default properties with a document. One of these are DocId.

image

The managed property DocId is of type text and marked as searchable, and you would assume you a search like DocId=123456 will bring back a result back.

image

For some reason this does not work. The workaround however is easy.

There exists a managed property called WorkId which is also returned per result, but it’s not visible in the search schema. This property is of type integer with the same value as DocId and you can bring back one item with the following query:

WorkId:123456 or WorkId=123456

You can also do WorkId<>123456 or -WorkId:123456 if you want all items except one item in particular.

Alternatively you can map the crawled property ows__dlc_DocId to a managed property of your choice and use that instead, but no reason to do that since another solution exists.

Friday, October 17, 2014

Using search to redirect a user to the correct home site

image
I was recently tasked with the following challenge.

Given a two-level site structure of Region and Country, a user should be redirected to the corresponding site to where he/she works. This means if you work in Norway you should be redirected to http://intranet/About/Europe/Norway. If you work in Germany, which doesn’t have a country site of it’s own, you should be redirected to the region site at http://intranet/About/Europe.
  • About
    • Europe
      • Norway
      • Sweden
      • Denmark
    • APAC
      • China
      • India
      • Japan
    • Central Office
The URL structure of the sites replicate the taxonomy used for settings the values in Active Directory which is synchronized to the User Profile Application.

Thursday, October 16, 2014

Retrieving and working with Search Navigation entries using CSOM

I’m currently working on some provisioning tasks for a search page and we want to script up the search navigation using CSOM. This would be the Everything, People, and Social tabs you see below the search box.
The issue is that Web.Navigation does not have the SearchNav property which SPWeb.Navigation has. It only has QuickLaunch and TopNavigationBar.
But just because the good guys over at Microsoft haven’t gotten around to implement all the SSOM properties doesn’t mean we’re stuck. Using Reflector I figured out the node id for the search navigation was 0x410. Which yields the following code.
string siteUrl = "http://dev/sites/search";

ClientContext clientContext = new ClientContext(siteUrl);
Web web = clientContext.Web;

var nav = web.Navigation;

NavigationNode searchNav = nav.GetNodeById(1040);
NavigationNodeCollection nodeCollection = searchNav.Children;

clientContext.Load(nodeCollection);
clientContext.ExecuteQuery();

foreach (NavigationNode navigationNode in nodeCollection)
{
    Console.WriteLine(navigationNode.Title + " : " + navigationNode.Url);
}

Take a look at http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.navigationnodecollection(v=office.15).aspx for sample code on how to add more nodes to the collection.

Enjoy!

Wednesday, October 15, 2014

S15E10: Search Orchestration - Page composition in rule major

Want the book? Go get it!

This is episode ten in the series “SharePoint Search Queries Explained - The Series”. See the intro post for links to all episodes.

This post covers two main objectives. Firstly how to configure search for any page to make it manageable in the long run, and secondly how to configure search for that same page to make the page show as fast as possible to the end-user.

The main tool used to accomplish this is Result Block Routing in a Query Rule. If you haven’t read about it before, now is certainly the time.

image

How to: Quickly switch audio input in Lync 2013

image

When I move my computer around I tend to plug in and out different headsets, and Lync more often than not have the wrong one set as the default one. This results in that I a lot of times when on voice calls have to hang up, click the cogwheel icon, then Tools and Audio Device Settings, and pick the right audio device.

I’ve done this ever since Lync 2013 was released… up until today when I discovered a clever icon in the lower right corner of Lync. With two clicks I can now pick my Logitech headset – and hopefully remember to do it before a call starts.

Tuesday, October 7, 2014

Creating a Delve clone using Content Search Web Part

While adding support for Office Graph queries in the SharePoint 2013 Query Tool I had to figure out how to send the query in as POST and not just GET. This led me into the Properties property of a search query. Basically a key value store which Microsoft can use to extend the search API’s over time without breaking anything. And this is what the Graph queries use.

There has been some great posts recently from Richard Dizerega, Elio Struyf and Waldek Mastykarz about the Office Graph. Both Richard and Waldek have used the REST API, while Elio did some nifty JavaScript in order to run queries. What’s missing in Elio’s approach is to get Graph data on the initial loading of results, as the web part will first perform a regular query before you can graph it up and re-trigger it. But, as long as you manage to encode it just right, it’s all about editing a web part definition in your favorite text editor.

See demo

Note: Using CSWP with the Office Graph has to be done in SPO, and is not available on-premises (except perhaps using hybrid which I haven't tested)

Monday, October 6, 2014

Get a list of the current user’s recent documents

When navigating to OneDrive in SharePoint Online you get a nice list on the left showing your recent documents. The list show documents you have recently used, that being opened/viewed or stored. I suspect this is sort of overlapping with My work in Delve, but different API’s and results.

image

A recent discussion internally about bringing relevant content to you on your start page, made me dig into this. Put it as part of your intranet home page, or filter the site on any project site, to show your most recent files. It’s all about you!

So, how do you get this list of documents? By using a REST call to the end-point

https://<tenant>.sharepoint.com/_api/me/getrecentdocs

If you add the usual headers of application/json;odata=verbose, you get the data back as JSON. If not, you get it as XML. For me it returned 31 items, more than enough for a good listing.

Saturday, October 4, 2014

Office Graph support in the SharePoint 2013 Search Query Tool

I just compiled v2.2 of the SharePoint 2013 Search Query Tool which has one major new function: Support to query the Office Graph in Office365 using GQL (Graph Query Language). Many thanks to Barry Waldbaum @ Microsoft for starting the work on this feature, and the joint effort to bring it into the tool.

Thursday, October 2, 2014

Caution when limiting results for a site collection

One way to limit results to the current site collection in for example a result source or search web part is to use the following query template:

{searchTerms} SiteID:{SiteCollection.ID}

Turns out that there is a bug in SharePoint on this (present in both SPO and on-prem at the time of writing) where the ID returned for the SiteCollection is the ID of the root web, not the ID of the site collection itself. As per the MSDN documentation it should return the GUID of the site collection where the query was issued.

The workaround is to use the URL instead of the ID.

{searchTerms} SPSiteURL:{SiteCollection}

Don’t use managed properties with a dot (but the fix is easy)

KQL does not work with managed properties having a . in the name. (FQL however does).

This means if you try to query against a managed property named for example mAdcOW.CoolProp, you will get zero results back.

Two possible solutions, either rename your property or give it an alias. Using an alias is probably the better solution and allows you to give nice readable names to your properties. The alias feature is also nice when dealing with the re-usable RefinableXXYY properties, so as to name them properly.

In my case an alias was the way as the property was auto generated from a scenario like this:
  1. Site column with internal name mAdcOW.CoolDate
  2. Auto generated crawled property: ows_q_DATE_mAdcOW.CoolDate
  3. Auto generated managed property: mAdcOW.CoolDateOWSDATE
  4. Mikael manually added alias mAdcOWCoolDate
Hence, mAdcOW.CoolDateOWSDATE:Z does not work, while mAdcOWCoolDate:Z does work.

Using .'s in internal column names is pretty common for programmers to divide namespaces as part of the name, and usually they work out well. You could always change the naming of column names to avoid the propagation of dots to managed properties, but using an alias will still yield prettier names.