The search experience was completely redesigned for Windows 8.1. From now on, the Windows Store apps are fully responsible for implementation of the in-app search functionality - Search Charm does not support Search Contract and does not trigger in-app search anymore.

The following screenshot demonstrates difference between Windows 8 and Windows 8.1 search results

Search - Windows 8 vs Windows 8.1

To facilitate this new design pattern, WinRT for Windows 8.1 includes a new search box UI control and a set of APIs for indexing and searching application data.

The new indexing functionality is based on the Windows Property System supported by WinRT since Windows 8 (see WinRT and Windows Property System). The Windows Store apps can use Windows Properties to annotate the data, add it to the index and use Advanced Query Syntax (AQS) to search it later.

There are two ways for indexing the data: by using Windows.Storage.Search APIs or by creating appcontent-ms files.

Using Windows.Storage.Search

The new IndexableContent class represents a unit of data for the indexing. It allows setting an ID to link the index with the actual data, defining data properties and supplying data for full-text indexing.

For example, email client can use IndexableContent for the individual emails:


IndexableContent content = new IndexableContent();
content.Id = "{90003c43-db8a-41ad-907b-567eab5dc468}";
content.Properties[Windows.Storage.SystemProperties.Keywords] = "draft";
content.Properties["System.Contact.EmailAddress"] = "contact@company.com"; 
content.Stream = ... // the email content as a stream

ContentIndexer class enables apps to generate per-app index for the content:


IndexableContent content = new IndexableContent();
…
await indexer.AddAsync(content);

ContentIndexer is also responsible for searching the indexed data:


var query = indexer.CreateQuery("keyword:draft", new[] { "System.Contact.EmailAddress"});
IReadOnlyList<IIndexableContent> drafts = await query.GetAsync();

First parameter for the CreateQuery is an AQS filter and the second parameter is a list of the properties to retrieve. These properties do not affect the query and application should not retrieve the properties it will not use.

This approach is useful when app already has some database and needs a way to simplify the search. The index should not be the main data storage as user can reset or delete it. ContentIndexer.Revision helps to keep the apps’ data storage and the index in sync.

appcontent-ms files

An alternative approach includes creation of the appcontent-ms files. Similar to IndexableContent objects, the appcontent-ms files include properties and indexable data. However, unlike the IndexableContent, appcontent-ms files can be used both for indexing and for storing the data.


<?xml version="1.0" encoding="utf-8"?>

<!-- The root node can have any name -->
<EmailAppData> 

  <!-- Well-known properties -->
  <Properties xmlns="http://schemas.microsoft.com/Search/2013/ApplicationContent">
    <Name>{90003c43-db8a-41ad-907b-567eab5dc468}</Name>
    <Keywords>
      <Keyword>draft</Keyword>
      <Keyword>work</Keyword>
    </Keywords>

    <!-- Other Windows Properties -->  
    <AdditionalProperties>
      <Property Key="System.Contact.EmailAddresses">
        <Value>user1@company.com</Value>
        <Value>user2@company.com</Value>
      </Property>
    </AdditionalProperties>
  </Properties>
  
  <!-- App specific nodes, can be indexed for full-text search -->  
  <MailBody sc:IndexableContent="true" 
            xmlns:sc="http://schemas.microsoft.com/Search/2013/ApplicationContent">E-mail text here</MailBody>
</EmailAppData>

These files can be created run-time or deployed as a part of the project. However, they should be placed in a very specific folder: to be indexed appcontent-ms files should be in an Indexed sub-folder of the Local or Roaming data folders.

The properly placed files are indexed and can be retrieved later using the file queries:


var queryOptions = new Windows.Storage.Search.QueryOptions();
queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.OnlyUseIndexer;
queryOptions.ApplicationSearchFilter = "keyword:draft";

StorageFolder indexedFolder = 
                await ApplicationData.Current.LocalFolder.CreateFolderAsync("Indexed",
                                 Windows.Storage.CreationCollisionOption.OpenIfExists);

var query = indexedFolder.CreateFileQueryWithOptions(queryOptions);
IReadOnlyList files = await query.GetFilesAsync();

// read data from the files…

The properties defined inside of appcontent-ms file treated by indexer as file’s properties and all AQS filters are fully supported.

Windows 8.1 Reading List uses appcontent-ms files for storing individual articles. Similarly, other Windows Store apps can use appcontent-ms for storing appropriate data and benefit from property indexing and full-text search.

References

  1. Using Advanced Query Syntax Programmatically
  2. Windows Property System Reference
  3. WinRT and Windows Property System
  4. Windows.Storage.Search namespace
  5. Indexer sample
blog comments powered by Disqus