Como gerenciar os resultados da pesquisa

Quando uma chamada de consulta é concluída normalmente, o resultado é um objeto Results. O objeto Results informa quantos documentos correspondentes foram encontrados no índice e quantos documentos correspondentes foram retornados. Nele, também está incluída uma coleção de ScoredDocuments correspondentes. A coleção geralmente contém uma parte de todos os documentos correspondentes encontrados, uma vez que a pesquisa retorna um número limitado de documentos cada vez que é chamada. Ao usar um desvio ou um cursor, você pode recuperar todos os documentos correspondentes, um subconjunto por vez.

Resultados

// index and query have already been defined ...
try {
    Results<ScoredDocument> result = index.search(query);
    long totalMatches = result.getNumberFound();
    int numberOfDocsReturned = result.getNumberReturned();
    Collection<ScoredDocument> listOfDocs = result.getResults();
} catch (SearchException e) {
    // handle exception...
}

Dependendo do valor da opção de consulta limit, o número de documentos correspondentes retornados no resultado pode ser inferior ao encontrado. Lembre-se de que o número encontrado será uma estimativa se a precisão dele for menor que o valor. Independentemente de como você configurar as opções de pesquisa, uma chamada search() não encontrará mais que 10 mil documentos correspondentes.

Se forem encontrados mais documentos do que os retornados e você quiser recuperar todos eles, precisará repetir a pesquisa usando um desvio ou um cursor, conforme explicado abaixo.

Documentos pontuados

Os resultados da pesquisa incluirão uma Coleção de ScoredDocuments correspondentes à consulta. Você pode recuperar a coleção usando o método getResults() ou iterar sobre os respectivos membros diretamente dos próprios resultados da pesquisa. Ambos os métodos são mostrados aqui:

// index and query have already been defined ...
Results<ScoredDocument> result = index.search(query);

// Grab the collection for later use:
Collection<ScoredDocument> theDocs = result.getResults();

// Alternatively, iterate over the results directly:
for (ScoredDocument doc : result) {
    // do work
}

Por padrão, um documento pontuado contém todos os campos do documento original indexados. Se as opções de consulta especificaram setFieldsToReturn, somente esses campos aparecerão nos resultados quando você chamar getFields() no documento. Se você usou addExpressionToReturn ou setFieldsToSnippet para criar campos calculados, recupere-os separadamente chamando getExpressions() no documento.

Como usar desvios

Se a pesquisa encontrar mais documentos do que é possível retornar de imediato, use um desvio a ser indexado na lista de documentos correspondentes. Por exemplo, o limite de consulta padrão é 20 documentos. Depois de executar uma pesquisa pela primeira vez (com o desvio 0) e recuperar os 20 primeiros documentos, recupere os 20 documentos seguintes definindo o desvio como 20 e executando a mesma pesquisa novamente. Continue repetindo a pesquisa, incrementando o deslocamento a cada vez com o número de documentos retornados:

// index and queryString have already been defined

try {
    int numberRetrieved = 0;
    int offset = 0;
    do {
        // build options and query
        QueryOptions options = QueryOptions.newBuilder()
            .setOffset(offset)
            .build();
        Query query = Query.newBuilder().setOptions(options).build(queryString);

        // search at least once
        Results<ScoredDocument> result = index.search(query);
        numberRetrieved = result.getNumberReturned();
        if (numberRetrieved > 0) {
            offset += numberRetrieved;
            // process the matched docs
        }

    }
    while (numberRetrieved > 0);
} catch (SearchException e) {
    // handle exception...
}

Os deslocamentos podem ser ineficientes na iteração sobre um conjunto de resultados muito grande.

Como usar cursores

Você também pode usar cursores para recuperar um subintervalo de resultados. Os cursores são úteis quando você pretende apresentar os resultados da pesquisa em páginas consecutivas e quer ter certeza de que não pulará nenhum documento no caso em que um índice seja modificado entre consultas. Os cursores também são mais eficientes na iteração em um conjunto de resultados muito grande.

Para usar cursores, é preciso criar um cursor inicial e incluí-lo nas opções de consulta. Há dois tipos de cursores, por consulta e por resultado. Um cursor por consulta faz com que um cursor separado seja associado ao objeto de resultado retornado pela chamada de pesquisa. Um cursor por resultado faz com que um cursor seja associado a cada documento pontuado nos resultados.

Como usar um cursor por consulta

Por padrão, um cursor recém-construído é um cursor por consulta. Ele mantém a posição do último documento retornado nos resultados da pesquisa e é atualizado a cada pesquisa. Para enumerar todos os documentos correspondentes em um índice, execute a mesma pesquisa até o resultado retornar um cursor nulo:

// index and queryString have already been defined

try {
    // create the initial cursor
    Cursor cursor = Cursor.newBuilder().build();

    do {
        // build options and query
        QueryOptions options = QueryOptions.newBuilder()
            .setCursor(cursor)
            .build();
        Query query = Query.newBuilder().setOptions(options).build(queryString);

        // search at least once
        Results<ScoredDocument> result = index.search(query);
        int numberRetrieved = result.getNumberReturned();
        cursor = result.getCursor();

        if (numberRetrieved > 0) {
            // process the matched docs
        }

    }
    while (cursor != null);
    // all done!
} catch (SearchException e) {
    // handle exception...
}

Como usar um cursor por resultado

Para criar cursores por resultado, é preciso definir a propriedade de cursor “perResult” como “true” ao criar o cursor inicial. Quando a pesquisa retornar, haverá um cursor associado a cada documento. Você pode usar esse cursor para especificar uma nova pesquisa com resultados que começam com um documento específico. Observe que, quando você passa um cursor por resultado para a pesquisa, não haverá nenhum cursor por consulta associado ao resultado. result.getCursor() retornará nulo, então não é possível usar isso para testar se todas as correspondências foram recuperadas.

// index and queryString have already been defined

try {
    // create an initial per-result cursor
    Cursor cursor = Cursor.newBuilder().setPerResult(true).build();
    // build options and query
    QueryOptions options = QueryOptions.newBuilder()
        .setCursor(cursor)
        .build();
    Query query = Query.newBuilder().setOptions(options).build(queryString);
    Results<ScoredDocument> result = index.search(query);

    // process the matched docs
    cursor = null;
    for (ScoredDocument doc : result) {
        // discover some document of interest and grab its cursor
        if (...)
            cursor = doc.getCursor();
     }

    // Start the next search from the document of interest
    if (cursor != null) {
        options = QueryOptions.newBuilder()
            .setCursor(cursor)
            .build();
        query = Query.newBuilder().setOptions(options).build(queryString);
        result = index.search(query);
    }
} catch (SearchException e) {
    // handle exception
}

Como salvar e restaurar cursores

Um cursor pode ser serializado como uma string segura na Web e, em seguida, restaurado para uso posterior:

String cursorString = cursor.toWebSafeString();
// Save the string ... and restore:
Cursor cursor = Cursor.newBuilder().build(cursorString));