Novembro de 2015

Volume 30, Número 12

Windows 10 - Acelerar as Operações de Arquivo com o Indexador de Pesquisa

Por Adam Wilson | Novembro de 2015

O indexador de pesquisa faz parte do Windows há diversas versões, fornecendo tudo, de exibições de biblioteca no Explorador de Arquivos à barra de endereços do IE, além de fornecer funcionalidades de pesquisa para o menu Iniciar e para o Outlook. Com o Windows 10, a força do indexador de pesquisa passou de limitada a computadores desktop a ser disponibilizada para todos os Aplicativos UWP (Plataforma Universal do Windows). Enquanto permite ao Cortana executar pesquisas aprimoradas, a parte mais interessante deste avanço é que ele aprimora muito a forma como os aplicativos interagem com o sistema de arquivos.

O indexador permite aos aplicativos fazer operações mais interessantes, como classificar e agrupar arquivos e acompanhar como o sistema de arquivos é modificado. A maioria das APIs do indexador está disponível para aplicativos UWP por meio dos namespaces Windows.Storage e Windows.Storage.Search. Os aplicativos já estão usando o indexador para permitir experiências melhores para seus usuários. Nesse artigo, explicarei como usar o indexador para acompanhar as alterações no sistema de arquivos, renderizar exibições de modo rápido e darei algumas dicas básicas sobre como aprimorar as consultas de um aplicativo.

Acessando Arquivos e Metadados Rapidamente

A maioria dos dispositivos de usuário contém centenas, ou milhares, de arquivos de mídia, incluindo fotos e músicas preferidas de um usuário. Aplicativos que podem iterar rapidamente pelos arquivos no dispositivo e oferecer interações estimulantes com os arquivos estão entre os aplicativos mais amados em qualquer plataforma. O UWP fornece diversas classes que podem ser usadas para acessar arquivos em qualquer dispositivo, independentemente do fator forma.

O namespace Windows.Storage inclui as classes básicas para acessar arquivos e pastas, bem como as operações de base que quase todos os aplicativos utilizam. Mas, se o seu aplicativo precisar acessar muitos arquivos e metadados, essas classes não fornecerão as características de desempenho que os usuários demandam.

Por exemplo, se você não controlar a pasta sendo enumerada, chamar StorageFolder.GetFilesAsync é a receita do desastre. Os usuários podem colocar bilhões de arquivos em um único diretório, mas tentar criar objetos StorageFile para cada um deles fará com que um aplicativo fique sem memória muito rápido. Mesmo em casos menos extremos, a chamada ainda será retornada de modo muito lento, pois o sistema precisa criar milhares de tratamentos de arquivo e realizar marshaling de volta para o contêiner de aplicativo. Para ajudar os aplicativos a evitar esta armadilha, o sistema fornece as classes StorageFileQueryResults e StorageFolderQueryResults.

StorageFileQueryResults é a classe a ser usada sempre que for gravar um aplicativo para tratar mais do que um número essencial de arquivos. Além de fornecer um modo bom de enumerar e modificar os resultados de uma consulta de pesquisa complexa, já que a API trata uma solicitação de enumeração como uma consulta para “*”, ela também funciona para casos mais simples.

Usar o indexador, quando disponível, é a primeira etapa para acelerar seu aplicativo. Agora, vindo de um gerente do programa indexador, parece como um apelo para manter meu emprego, mas há um motivo lógico para eu falar isso. Os objetos StorageFile e StorageFolder foram criados com o indexador em mente. As propriedades em cache no objeto podem ser recuperadas rapidamente por meio do indexador. Se você não estiver usando o indexador, o sistema precisará pesquisar os valores do disco e Registro, que têm uso intensivo de E/S e causam problemas de desempenho para o aplicativo e para o sistema.

Para garantir que o indexador seja usado, crie um objeto Query­Options e defina a propriedade QueryOptions.IndexerOption para usar somente o indexador:

QueryOptions options = new QueryOptions();
options.IndexerOption = IndexerOption.OnlyUseIndexer;

ou usar o indexador quando ele estiver disponível:

options.IndexerOption = IndexerOption.UseIndexerWhenAvailable;

O uso recomendado é para casos em que uma operação de arquivo lenta não bloqueará seu aplicativo ou enfraquecerá o UX para usar IndexerOption.Use­IndexerWhenAvailable. Ele tentará usar o indexador para enumerar arquivos, mas voltará para as operações de disco muito mais lentas, se necessário. O IndexerOption.OnlyUseIndexer é usado de modo aprimorado quando não retorna nenhum resultado, sendo melhor do que aguardar uma operação de arquivo lenta. O sistema não retornará nenhum resultado se o indexador estiver desabilitado, mas retornará rapidamente, permitindo que os aplicativos reativem o usuário.

Há vezes em que criar um objeto QueryOptions parece um pouco excessivo apenas para uma enumeração rápida e, nesses casos, pode ser melhor não se preocupar se o indexador estiver presente. Para casos em que você controla o conteúdo da pasta, recomenda-se chamar StorageFolder.GetItemsAsync. É uma linha de código fácil de ser gravada e quaisquer problemas de desempenho serão ocultados nos casos em que há somente alguns arquivos no diretório.

Outra maneira de acelerar a enumeração do arquivo é não criar objetos StorageFile ou StorageFolder desnecessários. Mesmo ao usar o indexador, abrir um StorageFile exige que o sistema crie um identificador de arquivo, colete alguns dados de propriedade e realize marshaling no processo do aplicativo. Este IPC é fornecido com atrasos inerentes, que podem ser evitados em muitos casos ao, simplesmente, não criar tais objetos.

Um ponto importante para ser observado é que um objeto StorageFileQueryResult com suporte do indexador não cria StorageFiles internamente. Eles são criados sob demanda quando solicitado pelo GetFilesAsync. Até que isso ocorra, o sistema somente mantém uma lista dos arquivos na memória, que são leves, se for compará-los.

A maneira recomendada de enumerar um grande número de arquivos é usar a funcionalidade de envio em lote em GetFilesAsync para a página em grupos de arquivos, conforme a necessidade. Dessa forma, seu aplicativo pode fazer o processamento em segundo plano nos arquivos enquanto aguarda o próximo conjunto ser criado. O código na Figura 1 mostra como isso é feito, com um exemplo simples.

Figura 1 - GetFilesAsync

uint index = 0, stepSize = 10;
IReadOnlyList<StorageFile> files = await queryResult.GetFilesAsync(index, stepSize);
index += 10;          
while (files.Count != 0)
{
  var fileTask = queryResult.GetFilesAsync(index, stepSize).AsTask();
  foreach (StorageFile file in files)
  {
    // Do the background processing here   
  }
  files = await fileTask;
  index += 10;
}

Este é o mesmo padrão de codificação que foi usado por diversos aplicativos já no Windows. Ao variar o tamanho da etapa, será possível obter o número correto de itens para ter uma primeira exibição dinâmica no aplicativo, enquanto prepara o restante dos arquivos no segundo plano.

A pré-busca de propriedade é outra maneira fácil de acelerar seu aplicativo. A pré-busca de propriedade permite ao seu aplicativo notificar o sistema se ele está interessado em determinado conjunto de propriedades do arquivo. O sistema capturará tais propriedades do indexador enquanto enumera um conjunto de arquivos e faz cache no objeto StorageFile. Isso fornece um aumento de desempenho em contrapartida à simples coleta dos fragmentos de propriedades quando os arquivos são retornados.

Defina os valores de pré-busca de propriedade no objeto QueryOptions. Alguns cenários comuns têm suporte ao usar Property­PrefetchOptions, mas os aplicativos também podem personalizar as propriedades solicitadas para qualquer valor com suporte do Windows. O código para fazer isso é simples:

QueryOptions options = new QueryOptions();
options.SetPropertyPrefetch(PropertyPrefetchOptions.ImageProperties,
  new String[] { });

Nesse caso, o aplicativo usa as propriedades da imagem e não precisa de outras propriedades. Quando o sistema enumera os resultados da consulta, faz cache das propriedades da imagem na memória para que elas estejam disponíveis de modo rápido posteriormente.

Uma última observação é que a propriedade precisa ser armazenada no índice para que a pré-busca ofereça ganho de desempenho; caso contrário, o sistema ainda não terá acesso ao arquivo para encontrar o valor, que é muito lento, se for compará-lo. A página do Centro de Desenvolvimento do Microsoft Windows para o sistema de propriedade (bit.ly/1LuovhT) tem todas as informações sobre as propriedades disponíveis no indexador do Windows. Pesquise isColumn = true na descrição da propriedade, o que indicará se a propriedade está disponível para ser pré-buscada.

Reunir todos esses aprimoramentos permite que seu código seja executado de modo muito mais rápido. Como um simples exemplo, gravei um aplicativo que recupera todas as imagens no meu computador juntamente com sua altura vertical. Essa é a primeira etapa que um aplicativo de exibição de imagem teria que fazer para exibir a coleção de fotos do usuário.

Fiz três execuções para conhecer os diferentes estilos de enumeração de arquivo e para mostrar as diferenças entre eles. O primeiro teste usou código ingênuo com o indexador habilitado, conforme mostrado na Figura 2. O segundo teste usou o código mostrado na Figura 3, que faz a pré-busca de propriedade e páginas nos arquivos. O terceiro usa a pré-busca de propriedade e a paginação de arquivo, mas com o indexador desabilitado. Esse código é o mesmo que na Figura 3, mas com uma linha alterada, como observado nos comentários.

Figura 2 - Código Ingênuo Enumerando uma Biblioteca

StorageFolder folder = KnownFolders.PicturesLibrary;
QueryOptions options = new QueryOptions(
  CommonFileQuery.OrderByDate, new String[] { ".jpg", ".jpeg", ".png" });          
options.IndexerOption = IndexerOption.OnlyUseIndexer;
StorageFileQueryResult queryResult = folder.CreateFileQueryWithOptions(options);
Stopwatch watch = Stopwatch.StartNew();          
IReadOnlyList<StorageFile> files = await queryResult.GetFilesAsync();
foreach (StorageFile file in files)
{                
  IDictionary<string, object> size =
    await file.Properties.RetrievePropertiesAsync(
    new String[] { "System.Image.VerticalSize" });
  var sizeVal = size["System.Image.VerticalSize"];
}           
watch.Stop();
Debug.WriteLine("Time to run the slow way: " + watch.ElapsedMilliseconds + " ms");

Figura 3 - Código Otimizado para Enumeração de uma Biblioteca

StorageFolder folder = KnownFolders.PicturesLibrary;
QueryOptions options = new QueryOptions(
  CommonFileQuery.OrderByDate, new String[] { ".jpg", ".jpeg", ".png" });
// Change to DoNotUseIndexer for trial 3
options.IndexerOption = IndexerOption.OnlyUseIndexer;
options.SetPropertyPrefetch(PropertyPrefetchOptions.None, new String[] { "System.Image.VerticalSize" });
StorageFileQueryResult queryResult = folder.CreateFileQueryWithOptions(options);
Stopwatch watch = Stopwatch.StartNew();
uint index = 0, stepSize = 10;
IReadOnlyList<StorageFile> files = await queryResult.GetFilesAsync(index, stepSize);
index += 10;
// Note that I'm paging in the files as described
while (files.Count != 0)
{
  var fileTask = queryResult.GetFilesAsync(index, stepSize).AsTask();
  foreach (StorageFile file in files)
  {
// Put the value into memory to make sure that the system really fetches the property
    IDictionary<string,object> size =
      await file.Properties.RetrievePropertiesAsync(
      new String[] { "System.Image.VerticalSize" });
    var sizeVal = size["System.Image.VerticalSize"];                   
  }
  files = await fileTask;
  index += 10;
}
watch.Stop();
Debug.WriteLine("Time to run: " + watch.ElapsedMilliseconds + " ms");

Ao observar os resultados com e sem a pré-busca, a diferença de desempenho é nítida, como mostrado na Figura 4.

Figura 4 - Resultados Com e Sem Pré-busca

Caso de Teste (2.600 imagens em um Computador Desktop) Tempo de Execução Médio de Mais de 10 Amostras
Código ingênuo + indexador 9.318 ms
Todas as otimizações + indexador 5.796 ms
Otimizações + sem indexador 20.248 ms (48.420 ms sem interesse)

Há uma chance de quase duplicar o desempenho do código ingênuo ao aplicar as otimizações simples descritas aqui. Os padrões também são rigorosamente testados. Antes de lançar uma versão do Windows, trabalhamos com as equipes de aplicativo para garantir que Fotos, Groove Música e outros funcionem da melhor maneira possível. É daí que esses padrões vêm; eles foram criados diretamente de um código dos primeiros aplicativos UWP no UWP e podem ser aplicados diretamente aos seus aplicativos.

Acompanhando Alterações no Sistema de Arquivos

Como mostrado aqui, a enumeração de todos os arquivos em um local é um processo com uso intensivo de recursos. Na maior parte do tempo, seus usuários nem vão ficar interessados nos arquivos antigos. Eles querem a foto que acabaram de tirar, a música que acabou de ser baixada ou o documento mais recentemente editado. Para ajudar a colocar os arquivos mais recentes no topo, seu aplicativo pode acompanhar as mudanças no sistema de arquivos e encontrar, de um jeito mais fácil, os arquivos criados ou alterados mais recentemente.

Há dois métodos para alterar o acompanhamento, dependendo se seu aplicativo está em segundo ou primeiro plano. Quando um aplicativo está no primeiro plano, ele pode usar o evento ContentsChanged de um objeto StorageFileQueryResult para ser notificado sobre alterações em determinada consulta. Quando um aplicativo está em segundo plano, ele pode registrar-se para StorageLibraryContentChangedTrigger para ser notificado quando algo for alterado. Ambas opções são notificações de poke (armazenamento em endereço na memória) para permitir que um aplicativo saiba quando algo foi alterado, mas não incluem informações sobre os arquivos que foram alterados.

Para encontrar quais arquivos foram modificados ou criados recentemente, o sistema fornece a propriedade System.Search.GatherTime. A propriedade é definida para todos os arquivos em um local indexado e acompanha a última vez que o indexador notou uma modificação no arquivo. Esta propriedade será constantemente atualizada com base no relógio do sistema, para que avisos de isenção de responsabilidade normais, envolvendo alterações de fuso horário, horário de verão e usuários modificando o relógio manualmente, continuem se aplicando na confiança desse valor em seu aplicativo.

É fácil registrar para alterar um evento de acompanhamento no primeiro plano. Ao criar um objeto StorageFileQueryResult abrangendo o escopo no qual o aplicativo está interessado, basta se registrar para o evento ContentsChanged, conforme mostrado aqui:

StorageFileQueryResult resultSet = photos.CreateFileQueryWithOptions(option);
resultSet.ContentsChanged += resultSet_ContentsChanged;

O evento será disparado sempre que algo no conjunto de resultados for alterado. Então, o aplicativo pode encontrar o arquivo, ou os arquivos, que foram alterados recentemente.

Para acompanhar alterações do segundo plano, é necessário estar um pouco mais envolvido. Os aplicativos podem se registrar para serem notificados quando um arquivo for alterado em uma biblioteca no dispositivo. Não há suporte para consultas ou escopos mais complexos, o que quer dizer que os aplicativos são responsáveis por parte do trabalho, para garantir que a alteração seja algo no qual eles têm realmente interesse.

Como uma observação interessante, o motivo pelo qual os aplicativos se registram apenas nas notificações de alteração da biblioteca, e não com base no tipo de arquivo, é devido à forma como o indexador foi criado. Filtrar consultas com base na localização de um arquivo no disco é muito mais rápido do que consultar uma correspondência com base no tipo de arquivo, além de ter reduzido o desempenho dos dispositivos em nossos testes iniciais. Fornecerei mais dicas de desempenho posteriormente, mas esse é um ponto importante a ser lembrado: filtrar resultados de consulta pela localização do arquivo é extremamente rápido, se comparado a outros tipos de operação de filtragem.

Destaquei as etapas para se registrar uma tarefa em segundo plano com exemplos de códigos em um post no blog (bit.ly/1iPUVIo), mas vamos nos aprofundar em algumas outras etapas mais interessantes aqui. A primeira coisa que um aplicativo deve fazer é criar o gatilho em segundo plano:

StorageLibrary library =
  await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
StorageLibraryContentChangedTrigger trigger =
  StorageLibraryContentChangedTrigger.Create(library);

O gatilho também pode ser criado por meio de uma coleção de bibliotecas se o aplicativo tiver interesse em acompanhar diversos locais. Nesse caso, o aplicativo analisará somente a biblioteca de fotos, que é um dos cenários mais comuns para aplicativos. Você precisa garantir que o aplicativo tenha a capacidade correta para poder acessar a biblioteca que está tentando alterar o acompanhamento; caso contrário, o sistema retornará uma exceção de acesso negado quando o aplicativo tentar criar um objeto StorageLibrary.

Em dispositivos móveis do Windows, esse item é especialmente poderoso, pois o sistema garante que novas imagens do dispositivo serão gravadas no local da biblioteca de fotos. Isso é feito independentemente do que o usuário seleciona na página de configurações, alterando quais pastas estão incluídas como parte da biblioteca.

O aplicativo deve registrar a tarefa em segundo plano usando Background­ExecutionManager e ter uma tarefa em segundo plano incorporada ao aplicativo. A tarefa em segundo plano pode ser ativada enquanto o aplicativo está no primeiro plano; portanto, todos os códigos devem estar cientes das condições de corrida em potencial no acesso de Registro ou de arquivo.

Quando o registro for concluído, seu aplicativo será chamado sempre que houver uma alteração na biblioteca na qual ele está registrado. Isso pode incluir arquivos nos quais seu aplicativo não tem interesse ou não pode processar. Nesse caso, aplicar um filtro restritivo assim que a tarefa em segundo plano for disparada é a melhor forma de garantir que não haja desperdício de processamento em segundo plano.

Encontrar os arquivos adicionados ou modificados mais recentemente é tão fácil quanto uma consulta única em um indexador. Basta solicitar todos os arquivos com um tempo de coleta no mesmo intervalo no qual o aplicativo está interessado. Os mesmos recursos de classificação e agrupamento disponíveis para outras consultas também podem ser usados aqui, se desejado. Esteja ciente de que o indexador usa o tempo Zulu internamente; portanto, lembre-se de converter todas as cadeias de hora para Zulu antes de usá-las. Veja como uma consulta pode ser desenvolvida:

QueryOptions options = new QueryOptions();
DateTimeOffset lastSearchTime = DateTimeOffset.UtcNow.AddHours(-1);
// This is the conversion to Zulu time, which is used by the indexer
string timeFilter = "System.Search.GatherTime:>=" +
  lastSearchTime.ToString("yyyy\\-MM\\-dd\\THH\\:mm\\:ss\\Z")
options.ApplicationSearchFilter += timeFilter;

Nesse caso, o aplicativo receberá todos os resultados da última hora. Em alguns aplicativos, faz mais sentido salvar o horário da última consulta e usá-lo na consulta, mas qualquer DateTimeOffset funcionará. Quando o aplicativo receber a lista de arquivos de volta, poderá enumerá-la, como discutido anteriormente, ou usar a lista para acompanhar quais arquivos são novos.

Combinar os dois métodos de acompanhamento de mudança com o horário de coleta permite aos aplicativos UWP a capacidade de alterar o acompanhamento do sistema de arquivos e reagir a alterações no disco com facilidade. Estas podem ser APIs relativamente novas no histórico do Windows, mas são usadas nos aplicativos Fotos, Groove Música, OneDrive, Cortana e Filmes e TVs no Windows 10. Você pode se sentir mais confiante ao incluí-los em seu aplicativo, sabendo que eles fornecem experiências incríveis.

Melhores Práticas Gerais

Há algumas coisas que um aplicativo usando o indexador deve saber para evitar bugs e garantir que o aplicativo funcione o mais rápido possível. Entre elas, deve-se evitar consultas complexas desnecessárias em partes de desempenho crítico do aplicativo, usar enumerações de propriedades corretamente e estar ciente dos atrasos de indexação.

Como uma consulta é criada por ter um impacto significativo em seu desempenho. Quando um indexador executa consultas em seu banco de dados de suporte, algumas consultas são mais rápidas devido à forma como as informações são posicionadas no disco. A filtragem com base na localização do arquivo é sempre mais rápida, pois o indexador consegue eliminar rapidamente partes grandes do indexador por meio da consulta. Isso economiza tempo de E/S e do processador, pois há algumas cadeias que precisam ser recuperadas e comparadas durante a pesquisa por correspondência com os termos de consulta.

O indexador é potente o suficiente para tratar expressões regulares, mas algumas formas delas são conhecidas por causar atrasos. A pior coisa que pode estar incluída em uma consulta de indexador é uma pesquisa de sufixo. Esta é uma consulta de todos os itens terminando com determinado valor. Um exemplo seria a consulta “*tion”, que pesquisa em todos os documentos contendo as palavras terminando com “tion”. Como o índice é classificado pela primeira letra em cada token, não há um modo mais rápido de encontrar os termos que correspondem a essa consulta. Ele precisa decodificar todos os tokens em todo o índice e compará-los ao termo de pesquisa, o que é extremamente lento.

As enumerações podem acelerar as consultas, mas têm um comportamento inesperado em compilações internacionais. Qualquer pessoa que desenvolveu um sistema de pesquisa sabe como é mais rápido fazer comparações com base em uma enumeração do que em cadeias. E isso também é igual para o indexador. Para facilitar para o aplicativo, o sistema de propriedade fornece diversas enumerações para filtrar resultados para menos itens antes de iniciar as comparações de cadeiras caras. Um exemplo comum disso é usar o filtro System.Kind para restringir o resultado para apenas os tipos de arquivos que um aplicativo pode tratar, como músicas ou documentos.

Há um erro comum que qualquer pessoa que usa enumerações deve estar ciente. Se o seu usuário vai procurar somente arquivo de música em uma versão dos EUA do Windows, adicionar System.Kind:=music à consulta vai funcionar perfeitamente para restringir os resultados da pesquisa e acelerar uma consulta. Isso também funcionará em outros idiomas, possivelmente o suficiente para ser aprovado em um teste de internacionalização, mas falhará quando o sistema não conseguir reconhecer “music” como um termo em inglês e fizer a análise no idioma local.

A maneira correta de usar uma enumeração, como System.Kind, é denotar com clareza que o aplicativo pretende usar o valor como uma enumeração, não como um termo de pesquisa. Isso é feito ao usar a sintaxe enumeration#value. Por exemplo, o jeito correto de filtrar somente resultados de música seria gravar System.Kind:=System.Kind#Music. Isso funcionará em todos os idiomas nos quais há Windows disponível e filtrará os resultados para somente arquivos que o sistema reconhece como arquivos de música.

Sair corretamente de uma AQS (Sintaxe de Consulta Avançada) pode ajudar a garantir que seus usuários não tenham dificuldade em reproduzir problemas de consulta. A AQS tem diversos recursos que permitem aos usuários incluir aspas ou parênteses para afetar como a consulta é processada. Isso quer dizer que os aplicativos precisam ter cuidado ao sair de termos de consulta que podem incluir esses caracteres. Por exemplo, a pesquisa por Document(8).docx resultará em um erro de análise e resultados incorretos retornados. Em vez disso, um aplicativo deve sair do termo como Document%288%29.docx. Isso retornará itens no índice que correspondem ao termo de pesquisa, em vez de fazer o sistema tentar analisar parênteses como parte da consulta.

Para obter uma abrangência mais profunda de todos os recursos diferentes da AQS e como garantir que suas consultas estejam corretas, é possível consultar a documentação em bit.ly/1Fhacfl. Você encontrará ótimas informações, incluindo mais detalhes sobre as dicas mencionadas aqui.

Uma observação sobre atrasos de indexação: a indexação não é instantânea, o que significa que os itens aparecendo no índice ou as notificações com base no indexador ficarão um pouco atrasadas a partir do momento em que o arquivo é gravado. Em uma carga normal de sistema, o atraso ocorrerá na ordem de 100 ms, o que é mais rápido do que a maioria dos aplicativos poder consultar o sistema de arquivos, para não ser notado. Há casos em que um usuário migra milhares de arquivos pelo computador e o indexador está, notavelmente, atrasado.

Nesses casos, recomenda-se que os aplicativos façam duas coisas: primeiro, você deve manter uma consulta aberta nos locais do sistema de arquivos nos quais o aplicativo tem mais interesse. Normalmente, isso é feito ao criar o objeto StorageFileQueryResult pelos locais do sistema de arquivos nos quais o aplicativo pesquisará. Quando o indexador notar que um aplicativo tem uma consulta em aberto, ele priorizará a indexação nesses escopos acima de todos os outros. Mas, lembre-se de não fazer isso para um escopo maior que o necessário. O indexador vai parar a retirada do sistema respectivo e as notificações ativas do usuário para processar as alterações o mais rápido possível, portanto, os usuários poderão notar um impacto no desempenho do sistema enquanto isso acontece.

A outra recomendação é avisar os usuários que o sistema está tentando alcançar as opções do arquivo. Alguns aplicativos, como o Cortana, mostram uma mensagem na parte superior da interface do usuário, enquanto outros vão parar de fazer consultas complexas e mostrar uma versão simples da experiência. Depende de você determinar o melhor para a experiência do seu aplicativo.

Conclusão

Essa foi uma análise rápida dos recursos disponíveis para clientes do indexador para as APIs do Windows Storage no Windows 10. Para obter mais informações sobre como usar as consultas para aprovar o contexto em uma ativação de aplicativo ou exemplos de códigos para o gatilho em segundo plano, veja o blog da equipe em bit.ly/1iPUVIo. Estamos trabalhando constantemente com desenvolvedores para garantir que as APIs de pesquisa sejam ótimas. Gostaríamos de ouvir seus comentários sobre o que está funcionando e o que você gostaria que fosse adicionado à superfície.


Adam Wilsoné gerente de programa na equipe de Ecossistema e Plataforma do Windows Developer. Ele trabalha na confiabilidade do indexador e da notificação por push do Windows. Anteriormente, trabalhou em APIs de armazenamento para Windows Phone 8.1. Entre em contato com ele pelo email adwilso@microsoft.com.

Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Sami Khoury
Sami Khoury é engenheiro na equipe de Ecossistema e Plataforma do Windows Developer. Ele lidera o desenvolvimento do Indexador do Windows