2013-02-27 20 views
8

Tôi có cơ sở dữ liệu trong tìm kiếm đàn hồi và muốn lấy tất cả các bản ghi trên trang web của tôi. Tôi đã viết một bean, kết nối với nút tìm kiếm đàn hồi, tìm kiếm các bản ghi và trả về một số phản hồi. mã java đơn giản của tôi, mà không tìm kiếm, là:trả lại tất cả các bản ghi trong một truy vấn trong tìm kiếm đàn hồi

SearchResponse response = getClient().prepareSearch(indexName).setTypes(typeName) .setQuery(queryString("*:*")).setExplain(true).execute().actionGet();

Nhưng elasticsearch thiết lập kích thước mặc định đến 10 và tôi có 10 lượt truy cập trong phản ứng. Có hơn 10 bản ghi trong cơ sở dữ liệu của tôi. Nếu tôi đặt kích thước thành Integer.MAX_VALUE, tìm kiếm của tôi trở nên rất chậm và đây không phải là điều tôi muốn.

Làm cách nào để có thể nhận tất cả các bản ghi trong một hành động trong một khoảng thời gian có thể chấp nhận mà không đặt kích thước phản hồi?

+0

Tôi cũng gặp vấn đề tương tự. Thans cho câu hỏi của bạn –

+0

Tôi có 100 tài liệu. Tôi đặt Integer.MAX_VALUE là size.Got OutOfMemoryError [Vùng heap Java] cũng có trong My Jboss. Nếu tôi cho 1000, sau đó làm việc tốt. –

Trả lời

0

Bạn sẽ phải trao đổi số lượng kết quả trả về so với thời gian bạn muốn người dùng đợi và số lượng bộ nhớ máy chủ khả dụng. Nếu bạn đã lập chỉ mục 1.000.000 tài liệu, không có cách nào thực tế để truy xuất tất cả các kết quả đó trong một yêu cầu. Tôi giả sử kết quả của bạn là dành cho một người dùng. Bạn sẽ phải xem xét làm thế nào hệ thống sẽ thực hiện dưới tải.

0

Để truy vấn tất cả, bạn nên xây dựng một CountRequestBuilder để nhận tổng số bản ghi (theo CountResponse) rồi đặt số trở lại kích thước yêu cầu tìm kiếm của bạn.

15
public List<Map<String, Object>> getAllDocs(){ 
     int scrollSize = 1000; 
     List<Map<String,Object>> esData = new ArrayList<Map<String,Object>>(); 
     SearchResponse response = null; 
     int i = 0; 
     while(response == null || response.getHits().hits().length != 0){ 
      response = client.prepareSearch(indexName) 
        .setTypes(typeName) 
         .setQuery(QueryBuilders.matchAllQuery()) 
         .setSize(scrollSize) 
         .setFrom(i * scrollSize) 
        .execute() 
        .actionGet(); 
      for(SearchHit hit : response.getHits()){ 
       esData.add(hit.getSource()); 
      } 
      i++; 
     } 
     return esData; 
} 
+0

Tác phẩm này hoạt động nhưng yêu cầu tải toàn bộ danh sách kết quả vào bộ nhớ, điều này là không cần thiết và thậm chí không thể cho các tập kết quả rất lớn. Một giải pháp mạnh mẽ hơn là sử dụng trình vòng lặp: http://stackoverflow.com/a/35729505/2091700 – Alphaaa

-1

1. đặt kích thước tối đa , ví dụ: MAX_INT_VALUE;

riêng cuối cùng tĩnh int MAXSIZE = 1000000;

@ Override công cộng Danh sách getAllSaleCityByCity (int cityId) throws Exception {

List<EsSaleCity> list=new ArrayList<EsSaleCity>(); 

    Client client=EsFactory.getClient(); 
    SearchResponse response= client.prepareSearch(getIndex(EsSaleCity.class)).setTypes(getType(EsSaleCity.class)).setSize(MAXSIZE) 
      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.boolFilter() 
        .must(FilterBuilders.termFilter("cityId", cityId)))).execute().actionGet(); 

    SearchHits searchHits=response.getHits(); 

    SearchHit[] hits=searchHits.getHits(); 
    for(SearchHit hit:hits){ 
     Map<String, Object> resultMap=hit.getSource(); 
     EsSaleCity saleCity=setEntity(resultMap, EsSaleCity.class); 
     list.add(saleCity); 
    } 

    return list; 

} 

2.count ES trước khi bạn tìm kiếm

CountResponse countResponse = client.prepareCount(getIndex(EsSaleCity.class)).setTypes(getType(EsSaleCity.class)).setQuery(queryBuilder).execute().actionGet(); 

int size = (int) countResponse.getCount() ; // đây là bạn muốn kích thước;

sau đó bạn có thể

SearchResponse response= client.prepareSearch(getIndex(EsSaleCity.class)).setTypes(getType(EsSaleCity.class)).setSize(size); 
+0

điều này sẽ phát nổ trong giai đoạn xác thực vì MAX_RESULT_WINDOW được đặt là 10000. bạn cần đặt giá trị cuộn trong PrepareSearch để tránh kịch bản. Có lẽ bằng cách sử dụng PrepareSearchScroll với Id cuộn từ đối tượng phản hồi của bạn sẽ là một giải pháp tốt hơn. –

0

Nếu trọng tâm chính của bạn là về xuất khẩu tất cả hồ sơ bạn có thể muốn đi cho một giải pháp mà không đòi hỏi bất kỳ loại phân loại, sắp xếp như là một hoạt động tốn kém. Bạn có thể sử dụng phương pháp quét và cuộn với ElasticsearchCRUD như mô tả here.

5

Câu trả lời xếp hạng cao nhất hiện tại hoạt động, nhưng nó yêu cầu tải toàn bộ danh sách kết quả vào bộ nhớ, có thể gây ra vấn đề bộ nhớ cho tập kết quả lớn và trong mọi trường hợp không cần thiết.

Tôi đã tạo một lớp Java thực hiện một số đẹp Iterator trên SearchHit s, cho phép lặp qua tất cả các kết quả. Bên trong, nó xử lý phân trang bằng cách đưa ra các truy vấn bao gồm trường from: và nó chỉ giữ trong bộ nhớ một trang kết quả.

Cách sử dụng:

// build your query here -- no need for setFrom(int) 
SearchRequestBuilder requestBuilder = client.prepareSearch(indexName) 
              .setTypes(typeName) 
              .setQuery(QueryBuilders.matchAllQuery()) 

SearchHitIterator hitIterator = new SearchHitIterator(requestBuilder); 
while (hitIterator.hasNext()) { 
    SearchHit hit = hitIterator.next(); 

    // process your hit 
} 

Lưu ý rằng, khi tạo bạn SearchRequestBuilder, bạn không cần phải gọi setFrom(int), vì điều này sẽ được thực hiện bởi các interally SearchHitIterator. Nếu bạn muốn chỉ định kích thước của một trang (nghĩa là số lần truy cập tìm kiếm trên mỗi trang), bạn có thể gọi setSize(int), nếu không giá trị mặc định của ElasticSearch được sử dụng.

SearchHitIterator:

import java.util.Iterator; 
import org.elasticsearch.action.search.SearchRequestBuilder; 
import org.elasticsearch.action.search.SearchResponse; 
import org.elasticsearch.search.SearchHit; 

public class SearchHitIterator implements Iterator<SearchHit> { 

    private final SearchRequestBuilder initialRequest; 

    private int searchHitCounter; 
    private SearchHit[] currentPageResults; 
    private int currentResultIndex; 

    public SearchHitIterator(SearchRequestBuilder initialRequest) { 
     this.initialRequest = initialRequest; 
     this.searchHitCounter = 0; 
     this.currentResultIndex = -1; 
    } 

    @Override 
    public boolean hasNext() { 
     if (currentPageResults == null || currentResultIndex + 1 >= currentPageResults.length) { 
      SearchRequestBuilder paginatedRequestBuilder = initialRequest.setFrom(searchHitCounter); 
      SearchResponse response = paginatedRequestBuilder.execute().actionGet(); 
      currentPageResults = response.getHits().getHits(); 

      if (currentPageResults.length < 1) return false; 

      currentResultIndex = -1; 
     } 

     return true; 
    } 

    @Override 
    public SearchHit next() { 
     if (!hasNext()) return null; 

     currentResultIndex++; 
     searchHitCounter++; 
     return currentPageResults[currentResultIndex]; 
    } 

} 

Trong thực tế, thực hiện như thế nào thuận tiện đó là để có một lớp như vậy, tôi tự hỏi tại sao khách hàng Java ElasticSearch của không cung cấp một cái gì đó tương tự.

+0

Nếu ai đó thêm hoặc xóa tài liệu, chúng tôi có đảm bảo rằng chúng tôi lặp lại tất cả tài liệu không? –

+1

Tôi nghĩ rằng việc sử dụng [cuộn] (https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-search-scrolling.html) sẽ mạnh mẽ hơn. –

+0

Nó phụ thuộc vào cách bạn soạn 'SearchRequestBuilder' của bạn. Ví dụ: nếu bạn sắp xếp kết quả theo ID tài liệu tăng dần và chỉ thêm tài liệu có ID tài liệu cao hơn, bạn sẽ lặp qua tất cả các kết quả. Câu trả lời này được viết cho ES 1.7, khi Scrolls chưa tồn tại. Họ có thể là một lựa chọn tốt hơn thực sự. – Alphaaa

2

Bạn có thể sử dụng API cuộn. Một gợi ý khác về việc sử dụng trình lặp tìm kiếm cũng sẽ hoạt động tốt, nhưng chỉ khi bạn không muốn cập nhật các lần truy cập đó.

import static org.elasticsearch.index.query.QueryBuilders.*; 

QueryBuilder qb = termQuery("multi", "test"); 

SearchResponse scrollResp = client.prepareSearch(test) 
     .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC) 
     .setScroll(new TimeValue(60000)) 
     .setQuery(qb) 
     .setSize(100).execute().actionGet(); //max of 100 hits will be returned for each scroll 
//Scroll until no hits are returned 
do { 
    for (SearchHit hit : scrollResp.getHits().getHits()) { 
     //Handle the hit... 
    } 

    scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(60000)).execute().actionGet(); 
} while(scrollResp.getHits().getHits().length != 0); // Zero hits mark the end of the scroll and the while loop.