2013-08-28 20 views
1

對於我正在處理的問題,我擁有大多數的父/子文檔解決方案,但我遇到了一個問題:從迭代的方面在我需要訪問父文檔字段的值的子文檔上。我有(或我可以得到)父文檔ID(從子文檔的_parent字段,或最壞的情況下,通過將其重新編入索引作爲普通字段),但這是一個「外部」ID,而不是節點內部ID需要從字段緩存中加載字段值。 (我使用的是默認的路由,以便父文檔肯定是在同一個碎片的孩子。)如何從兒童文檔的自定義方面訪問ElasticSearch parent-doc字段

更具體而言,這裏就是我在FacetCollector至今(ES 0.20.6):

protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { 
    /* not sure this will work, otherwise I can index the field seperately */ 
    parentFieldData = (LongFieldData) fieldDataCache.cache(FieldDataType.DefaultTypes.LONG, reader, "_parent"); 
    parentSpringinessFieldData = (FloatFieldData) fieldDataCache.cache(FieldDataType.DefaultTypes.FLOAT, "springiness"); 
    /* ... */ 

protected void doCollect(int doc) throws IOException { 
    long parentID = parentFieldData.value(doc); // or whatever the correct equivalent here is 
    // here's the problem: 
    parentSpringiness = parentSpringinessFieldData.value(parentID) 
    // type error: expected int (node-internal ID), got long (external ID) 

有什麼建議嗎? (我不能升級到0.90,但會有興趣聽到這是否會有所幫助。)

回答

0

聲望很好的免責聲明:(1)我最終沒有使用這種方法,所以這只是稍微測試的代碼,(2)盡我所見,這將會非常低效,並且它具有與父查詢相同的內存開銷。如果另一種方法適用於您,請考慮它(對於我的使用情況,我最終使用了嵌套文檔,使用迭代嵌套文檔和父文檔的自定義方面收集器輕鬆訪問兩者的字段值) 。

工作ES代碼中的示例是org.elasticsearch.index.search.child.ChildCollector。你需要的第一個元素是收集初始化:

try { 
     context.idCache().refresh(context.searcher().subReaders()); 
    } catch (Exception e) { 
     throw new FacetPhaseExecutionException(facetName, "Failed to load parent-ID cache", e); 
    } 

這使得有可能以下行doSetNextReader()

typeCache = context.idCache().reader(reader).type(parentType); 

它給你父文檔的UID的doCollect(int childDocId)查找:

HashedBytesArray postingUid = typeCache.parentIdByDoc(childDocId); 

父文檔不一定會在與子文檔相同的讀取器中找到:當收集器初始化時,您還需要存儲所有r讀者(需要訪問字段值)和每個讀者IdReaderTypeCache(將父文檔的UId解析爲讀者內部docId)。

this.readers = new Tuple[context.searcher().subReaders().length]; 
    for (int i = 0; i < readers.length; i++) { 
     IndexReader reader = context.searcher().subReaders()[i]; 
     readers[i] = new Tuple<IndexReader, IdReaderTypeCache>(reader, context.idCache().reader(reader).type(parentType)); 
    } 
    this.context = context; 

然後,當你需要的父文檔領域,你必須遍歷尋找正確的讀/ typecache對:

 int parentDocId = -1; 
     for (Tuple<IndexReader, IdReaderTypeCache> tuple : readers) { 
      IndexReader indexReader = tuple.v1(); 
      IdReaderTypeCache idReaderTypeCache = tuple.v2(); 
      if (idReaderTypeCache == null) { // might be if we don't have that doc with that type in this reader 
       continue; 
      } 
      parentDocId = idReaderTypeCache.docById(postingUid); 
      if (parentDocId != -1 && !indexReader.isDeleted(parentDocId)) { 
       FloatFieldData parentSpringinessFieldData = (FloatFieldData) fieldDataCache.cache(
         FieldDataType.DefaultTypes.FLOAT, 
         indexReader, 
         "springiness"); 
       parentSpringiness = parentSpringinessFieldData.value(parentDocId); 
       break; 
      } 
     } 
     if (parentDocId == -1) { 
      throw new FacetPhaseExecutionException(facetName, "Parent doc " + postingUid + " could not be found!"); 
     }