検索結果の処理

クエリ呼び出しが正常に終了すると、その結果が Results オブジェクトとして返されます。Results オブジェクトによって、インデックス内に見つかった一致ドキュメントの数と返された一致ドキュメントの数がわかります。また、このオブジェクトには一致する ScoredDocuments のコレクションも含まれています。検索で呼び出しのたびに返せるドキュメントの数には制限があるため、通常コレクションには見つかったドキュメントの一部しか含まれません。オフセットやカーソルを使用して、検索条件に一致するドキュメントのサブセットの取得を繰り返すことによって、最終的に該当するドキュメントをすべて取得できます。

結果

// 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...
}

limit クエリ オプションの値によっては、結果で返される一致ドキュメントの数が、見つかった数より少ない場合があります。見つかった数の精度が、見つかった数より低い場合に、見つかった数は推定数になるので注意してください。検索オプションの構成にかかわらず、1 度の search() 呼び出しで検出できる一致ドキュメントの数は最大 10,000 個です。

返されたドキュメントより多くのドキュメントが見つかり、それらすべてを取得する必要がある場合は、後述のように、オフセットやカーソルを使用して検索を繰り返す必要があります。

スコア付きドキュメント

検索結果には、クエリに一致する ScoredDocuments のコレクションが含まれます。メソッド getResults() を使用してコレクションを取得するか、または検索結果自体で反復処理を行ってそのメンバーに直接アクセスできます。両方のやり方を次に示します。

// 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
}

デフォルトでスコア付きドキュメントには、インデックス化された元のドキュメントのすべてのフィールドが含まれます。クエリ オプションsetFieldsToReturn を指定した場合、ドキュメントに対して getFields() を呼び出すと、それらのフィールドのみが結果に表示されます。addExpressionToReturn または setFieldsToSnippet を使用して計算済みフィールドを作成した場合、それらを個別に取得するには、ドキュメントに対して getExpressions() を呼び出します。

オフセットの使用

検索で、一度に返せる数より多くのドキュメントが見つかった場合、オフセットを使用して、一致するドキュメントのリストへのインデックスを作成します。たとえば、デフォルトのクエリ制限が 20 ドキュメントであるとします。検索を初めて実行し(オフセット 0 で)、最初の 20 ドキュメントを取得した後に、オフセットを 20 に設定し、同じ検索を再実行して、次の 20 ドキュメントを取得します。オフセットを返されるドキュメント数分増やしながら検索を繰り返します。

// 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...
}

オフセットはきわめて大きな結果セットに対して繰り返す場合、非効率的になることがあります。

カーソルの使用

カーソルを使用して、結果の部分範囲を取得することもできます。カーソルは、連続したページに検索結果を表示しようとし、クエリ間でインデックスが変更された可能性がある場合でもすべてのドキュメントをスキップしないようにする場合に便利です。また、カーソルはきわめて大きな結果セットを繰り返す場合にも効率的です。

カーソルを使用するには、初期カーソルを作成し、それをクエリ オプションに含める必要があります。クエリごとと結果ごとの 2 種類のカーソルがあります。クエリごとのカーソルを使用すると、検索呼び出しによって返される結果オブジェクトごとに個別のカーソルが関連付けられます。結果ごとのカーソルでは、結果内のすべてのスコア付きドキュメントにカーソルが関連付けられます。

クエリごとのカーソルの使用

デフォルトで、新しく構築されるカーソルはクエリごとのカーソルです。このカーソルは、検索の結果で返された最後のドキュメントの位置を保持します。これは検索ごとに更新されます。インデックス内の一致するすべてのドキュメントを列挙するには、結果で null カーソルが返されるまで同じ検索を実行します。

// 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...
}

結果ごとのカーソルの使用

結果ごとのカーソルを作成するには、初期カーソルの作成時に、カーソルの perResult プロパティを true に設定する必要があります。検索が返されると、すべてのドキュメントにカーソルが関連付けられます。そのカーソルを使用して、新たな検索を実行する際に特定のドキュメントから始まる結果を返すよう指定できます。結果ごとのカーソルを検索に渡した場合、結果自体にはクエリごとのカーソルが関連付けられないことに注意してください。このとき result.getCursor() は null を返すため、これを使用して一致するすべてのドキュメントを取得したかどうかを検知することはできません。

// 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
}

カーソルの保存と復元

カーソルは後で使用するためにウェブセーフ文字列としてシリアル化し、保存して復元できます。

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