Jamie McLaughlin
Jamie McLaughlin

Reputation: 562

Working Lucene SearchAfter Example

I'm trying to use Lucene 4.8.1's SearchAfter methods to implement paging of search results in a web application.

A similar question has been asked before, but the accepted answer given there does not work for me:

Stack Overflow Question: Lucene web paging

When I create a Lucene ScoreDoc from scratch in this way to use as an argument for SearchAfter:

   ScoreDoc sd = new ScoreDoc(14526, 0.0f);
   TopDocs td = indexSearcher.searchAfter(sd, query, null, PAGEHITS);

I get this exception:

java.lang.IllegalArgumentException: after must be a FieldDoc

This appears contrary to the documentation. But in any case, when I create a Field Doc instead, I get:

java.lang.IllegalArgumentException: after.fields wasn't set

after.fields is an Object array, so I can hardly set that with information I can pass in a URI!

I cannot find any working code examples using SearchAfter. My original plan was obviously to create a new ScoreDoc as the previous question suggests. Can anybody suggest what I might be doing wrong, or link to any working code examples of SearchAfter?

Thanks!

Upvotes: 3

Views: 2489

Answers (2)

spring
spring

Reputation: 1

can you have a try.

@Test
public void searchAfter() {
    Object[] objects = new Object[]{"1"};
    List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
    boolean type = true;
    while (type) {
        SearchHits searchHits = searchAfter(objects);
        SearchHit[] hits = searchHits.getHits();
        if (hits != null && hits.length > 0){
            objects = hits[hits.length-1].getSortValues();
            if (hits.length < size) type = false;
            for (SearchHit hit : hits) {
                data.add(hit.getSourceAsMap());
                System.out.println(JsonUtil.objectToJson(hit.getSourceAsMap()));
            }
        }

    }
    Iterator<Map<String, Object>> iterator = data.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next().toString());
    }
    System.out.println(data.size() + "-----------------");

}

public SearchHits searchAfter(Object[] objects) {
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.termQuery("age", "33"));
    sourceBuilder.size(size);
    sourceBuilder.sort("account_number", SortOrder.ASC);
    sourceBuilder.searchAfter(objects);

    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("bank");
    searchRequest.source(sourceBuilder);
    ActionFuture<SearchResponse> response = elasticsearchTemplate.getClient().search(searchRequest);

    SearchHits searchHits = response.actionGet().getHits();
    return searchHits;
}

Upvotes: 0

jamie
jamie

Reputation: 724

I don't believe you can create a scoredoc and then pass it to searchAfter. You need to use the ScoreDocs returned from a previous search.

Upvotes: 2

Related Questions