2013-02-27 21 views
8

मेरे पास लोचदार खोज में एक डेटाबेस है और मैं अपने वेब पेज पेज पर सभी रिकॉर्ड प्राप्त करना चाहता हूं। मैंने एक बीन लिखा, जो लोचदार खोज नोड से जुड़ता है, रिकॉर्ड खोजता है और कुछ प्रतिक्रिया देता है। मेरे सरल जावा कोड है, जो खोज करता है, है:लोचदार खोज में एक प्रश्न में सभी रिकॉर्ड लौटाएं

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

लेकिन 10 elasticsearch सेट डिफ़ॉल्ट आकार और मैं जवाब में 10 हिट है। मेरे डेटाबेस में 10 से अधिक रिकॉर्ड हैं। यदि मैं Integer.MAX_VALUE पर आकार सेट करता हूं तो मेरी खोज बहुत धीमी हो जाती है और यह वही नहीं है जो मैं चाहता हूं।

प्रतिक्रिया के आकार के बिना स्वीकार्य समय में एक ही कार्रवाई में सभी रिकॉर्ड्स कैसे प्राप्त कर सकते हैं?

+0

मुझे भी यही समस्या है। आपके प्रश्न के लिए Thans –

+0

मेरे पास 100 दस्तावेज़ हैं। मैं integer.MAX_VALUE को आकार के रूप में सेट करता हूं। गॉट आउटऑफमेमरी एरर [जावा हीप स्पेस] माई जब्स में भी। अगर मैं 1000 देता हूं, तो ठीक काम करता है। –

उत्तर

0

आपको लौटाए गए परिणामों की संख्या को उस समय बनाम करना होगा जब आप उपयोगकर्ता को प्रतीक्षा करना चाहते हैं और उपलब्ध सर्वर मेमोरी की मात्रा। यदि आपने 1,000,000 दस्तावेज़ों को अनुक्रमित किया है, तो उन सभी परिणामों को एक अनुरोध में पुनर्प्राप्त करने का यथार्थवादी तरीका नहीं है। मुझे लगता है कि आपके परिणाम एक उपयोगकर्ता के लिए हैं। आपको यह विचार करना होगा कि सिस्टम लोड के तहत कैसे कार्य करेगा।

0

सभी को पूछने के लिए, आपको रिकॉर्ड की कुल संख्या (काउंटर रेस्पॉन्स द्वारा) प्राप्त करने के लिए काउंटरआरक्वेटबिल्डर बनाना चाहिए, फिर नंबर को अपने सीच अनुरोध के आकार पर सेट करें।

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

यह काम करता है, लेकिन परिणामों की पूरी सूची को स्मृति में लोड करने की आवश्यकता है, जो अनावश्यक है, और यहां तक ​​कि बहुत बड़े परिणाम सेट के लिए भी असंभव है। इटरेटर्स का उपयोग करने के लिए एक और मजबूत समाधान है: http://stackoverflow.com/a/35729505/2091700 – Alphaaa

-1

1. अधिकतम आकार को सेट करें, उदाहरण: MAX_INT_VALUE;

निजी स्थिर अंतिम int MAXSIZE = 1000000;

@Override सार्वजनिक सूची getAllSaleCityByCity (पूर्णांक cityId) फेंकता अपवाद {

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 इससे पहले कि आप

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

पूर्णांक आकार = (int) countResponse.getCount() खोज ; // यह आप आकार चाहते हैं;

तो आप कर सकते हैं

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

यह सत्यापन चरण में विस्फोट हो जाएगा क्योंकि MAX_RESULT_WINDOW 10000 के रूप में सेट किया गया है। आपको स्क्रॉल मान को readySearch से बचने के लिए सेट करना होगा परिदृश्य। शायद आपकी प्रतिक्रिया ऑब्जेक्ट से स्क्रॉल आईडी के साथ readySearchScroll का उपयोग करना एक बेहतर समाधान होगा। –

0

अपने प्राथमिक ध्यान, सभी रिकॉर्ड आप एक समाधान है जो छँटाई के किसी भी प्रकार की आवश्यकता नहीं है के लिए जाना चाहते हो सकता है निर्यात पर है, तो के रूप में छंटाई एक महंगी ऑपरेशन है। आप वर्णित here के रूप में वर्णित ElasticsearchCRUD के साथ स्कैन और स्क्रॉल दृष्टिकोण का उपयोग कर सकते हैं।

5

वर्तमान उच्चतम रैंकिंग उत्तर काम करता है, लेकिन इसे परिणामों की पूरी सूची को स्मृति में लोड करने की आवश्यकता होती है, जो बड़े परिणाम सेट के लिए स्मृति समस्याएं पैदा कर सकती है, और किसी भी मामले में अनावश्यक है।

मैंने एक जावा क्लास बनाया है जो SearchHit से अधिक अच्छा बनाता है, जो सभी परिणामों के माध्यम से पुन: सक्रिय करने की अनुमति देता है। आंतरिक रूप से, यह from: फ़ील्ड को शामिल करने वाले प्रश्नों को जारी करके पृष्ठांकन को संभालता है, और यह केवल मेमोरी के एक पृष्ठ में रहता है।

उपयोग:

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

ध्यान दें कि, जब बनाने अपने SearchRequestBuilder, आप setFrom(int) कॉल करने के लिए, के रूप में यह SearchHitIterator द्वारा interally किया जाएगा जरूरत नहीं है। यदि आप किसी पृष्ठ का आकार निर्दिष्ट करना चाहते हैं (यानी प्रति पृष्ठ खोज हिट की संख्या), तो आप setSize(int) पर कॉल कर सकते हैं, अन्यथा लोचदार खोज का डिफ़ॉल्ट मान उपयोग किया जाता है।

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]; 
    } 

} 

वास्तव में, को साकार कैसे सुविधाजनक यह, मुझे आश्चर्य है कि इस तरह के एक वर्ग के लिए क्यों ElasticSearch के जावा ग्राहक कुछ इसी तरह की पेशकश नहीं करता है।

+0

यदि कोई अन्य दस्तावेज़ जोड़ता या हटाता है, तो क्या हमारे पास गारंटी है कि हम सभी दस्तावेजों पर पुन: प्रयास करते हैं? –

+1

मुझे लगता है कि [स्क्रॉल] का उपयोग करना (https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-search-scrolling.html) अधिक मजबूत होना चाहिए। –

+0

यह इस बात पर निर्भर करता है कि आप अपने 'SearchRequestBuilder' को कैसे लिखते हैं। उदाहरण के लिए, यदि आप आरोही दस्तावेज़ आईडी द्वारा परिणामों को सॉर्ट करते हैं, और केवल उच्च दस्तावेज़ आईडी के साथ दस्तावेज़ जोड़ते हैं, तो आप सभी परिणामों के माध्यम से फिर से शुरू हो जाएंगे। यह उत्तर ES 1.7 के लिए लिखा गया था, जब स्क्रॉल अभी तक मौजूद नहीं था। वे वास्तव में एक बेहतर विकल्प हो सकता है। – Alphaaa

2

आप स्क्रॉलिंग API का उपयोग कर सकते हैं। सर्चहाइट इटरेटर का उपयोग करने का दूसरा सुझाव भी बहुत अच्छा काम करेगा, लेकिन केवल तभी जब आप उन हिट को अपडेट नहीं करना चाहते हैं।

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. 
संबंधित मुद्दे