content: package org.apache.solr.request.join;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Map.Entry;
  
  import org.apache.log4j.Logger;
  import org.apache.lucene.index.SegmentReader;
  import org.apache.lucene.index.Term;
  import org.apache.lucene.index.TermDocs;
  import org.apache.lucene.index.TermEnum;
  import org.apache.solr.request.join.HigoJoin.IntArr;
  import org.apache.solr.schema.FieldType;
  import org.apache.solr.schema.IndexSchema;
  import org.apache.solr.schema.TrieField;
  import org.apache.solr.search.BitDocSet;
  import org.apache.solr.search.DocIterator;
  import org.apache.solr.search.DocSet;
  import org.apache.solr.search.SolrIndexSearcher;
  
  
  public class HigoJoinSingleValues implements HigoJoinInterface{
  	private static Logger LOG = Logger.getLogger(HigoJoinSingleValues.class);
  	private SolrIndexSearcher readerleft;
  	private SolrIndexSearcher readerright;
  	private String fieldLeft;
  	private String fieldRigth;
  	public HigoJoinSingleValues(SolrIndexSearcher readerleft,
  			SolrIndexSearcher readerright, String fieldLeft, String fieldRigth) throws IOException {
  		this.readerleft = readerleft;
  		this.readerright = readerright;
  		this.fieldLeft = fieldLeft;
  		this.fieldRigth = fieldRigth;
  		this.makejoin();
  	}
  	
  	public HigoJoinSingleValues(SegmentReader reader,String partion,IndexSchema schema,
  			SolrIndexSearcher readerright, String fieldLeft, String fieldRigth) throws IOException {
  		this.readerleft = null;
  		this.schema=schema;
  		this.leftreader=reader;
  		this.readerright = readerright;
  		this.fieldLeft = fieldLeft;
  		this.fieldRigth = fieldRigth;
  		this.makejoin();
  	}
  	
  
  	private SegmentReader leftreader=null;
  	private IndexSchema schema;
  	
  	long memsize = -1;
  
  	@Override
  	public synchronized long memSize() {
  		if (memsize >= 0) {
  			return memsize;
  		}
  
  		memsize = 256;
  		memsize+=join.length*4;
  		memsize+=joinRevert.length*8;
  		
  		for(int[] list:this.join){
  			if(list!=null)
  			{
  				memsize+=list.length*8;
  			}
  		}
  		return memsize;
  	}
  
  		@Override
  		public void LRUclean() {
  			
  		}
  	  
  		
  	int[][] join=null;
  	private int[] joinRevert=null;
  	public DocSet filterByRight(DocSet leftDocs,DocSet rightDocs)
  	{
  		BitDocSet docset=new BitDocSet();
  		DocIterator iter = rightDocs.iterator();
  		while (iter.hasNext()) {
  			int doc = iter.nextDoc();
  			int[] list=join[doc];
  			if(list==null)
  			{
  				continue;
  			}
  			for(int jp:list)
  			{
  				docset.add(jp);
  			}
  		}
  		
  		return leftDocs.intersection(docset);
  	}
  	
  	
  	public Integer getRight(int leftDocid,int termNum)
  	{
  		int rtn=joinRevert[leftDocid];
  		if(rtn<0)
  		{
  			return null;
  		}
  		return rtn;
  	}
  
  	
  	
  	private IntArr getListArr(TermEnum teLeft,TermDocs tdleft,int[] docs,int[] freqs,int limit) throws IOException
  	{
  
  		IntArr LeftArr=new IntArr();
  
  		ArrayList<Integer> jpleft=new ArrayList<Integer>();
  		tdleft.seek(teLeft);
  		int index=0;
  		for (;;) {
  			int n = tdleft.read(docs, freqs);
  			if (n <= 0) {
  				break;
  			}
  			for (int i = 0; i < n; i++) {
  				if(index<limit)
  				{
  					index++;
  					jpleft.add(docs[i]);
  				}else{
  					break;
  				}
  				
  			}
  		}
  		
  		LeftArr.list=new int[jpleft.size()];
  		index=0;
  		for(Integer d:jpleft)
  		{
  			LeftArr.list[index]=d;
  			index++;
  		}
  		
  		return LeftArr;
  	}
  	private void makejoin() throws IOException
  	{
  		IndexSchema schema=null;
  		if(this.leftreader!=null)
  		{
  			schema=this.schema;
  		}else{
  			schema=readerleft.getSchema();
  		}
  		
  		FieldType ftleft=schema.getFieldType(fieldLeft);
  		
  		String prefixLeft=TrieField.getMainValuePrefix(ftleft);
  		Term tiLeft=new Term(fieldLeft, prefixLeft==null?"":prefixLeft);
  		TermEnum teLeft = null;
  		TermDocs tdleft=null;
  		if(this.leftreader!=null)
  		{
  			this.joinRevert=new int[this.leftreader.maxDoc()+1];
  			tdleft=this.leftreader.termDocs();
  			teLeft=this.leftreader.terms(tiLeft);
  		}else{
  			this.joinRevert=new int[readerleft.getReader().maxDoc()+1];
  			teLeft=readerleft.getReader().terms(tiLeft);
  			tdleft=readerleft.getReader().termDocs();
  		}
  		
  		for(int i=0;i<this.joinRevert.length;i++)
  		{
  			this.joinRevert[i]=-1;
  		}
  		
  
  		
  		FieldType ftright =readerright.getSchema().getFieldType(fieldRigth);
  		String prefixRight=TrieField.getMainValuePrefix(ftright);
  		Term tiRight=new Term(fieldRigth, prefixRight==null?"":prefixRight);
  		
  		TermEnum teRight = readerright.getReader().terms(tiRight.createTerm(prefixRight==null?"":prefixRight));
  		TermDocs tdRight=readerright.getReader().termDocs();
  		this.join=new int[readerright.getReader().maxDoc()+1][];
  		for(int i=0;i<this.join.length;i++)
  		{
  			this.join[i]=null;
  		}
  		
  		int[] docs = new int[1000];
  		int[] freqs = new int[1000];
  		
  		
  		int debugline=0;
  		
  		HashMap<Integer,HashSet<Integer>> join_tmp=new HashMap<Integer,HashSet<Integer>>();
  //		HashMap<Integer,Integer> joinRevert_tmp=new HashMap<Integer,Integer>();
  		for (;;) {
  			Term tleft= teLeft.term();
  			Term tRight=teRight.term();
  			
  			
  			if (tleft == null||tRight==null) {
  				LOG.info("###termbreak###"+String.valueOf(tleft)+">>>>"+String.valueOf(tRight)+","+fieldLeft+","+fieldRigth);
  				break;
  			}
  			if((!tleft.field().equals(fieldLeft))||(!tRight.field().equals(fieldRigth)))
  			{
  				LOG.info("###termbreak fieldchange###"+String.valueOf(tleft)+">>>>"+String.valueOf(tRight)+","+fieldLeft+","+fieldRigth);
  				break;
  			}
  			
  			String tvleft=ftleft.indexedToReadable(tleft.text());
  			String tvRight=ftright.indexedToReadable(tRight.text());
  
  
  			if(tvleft.equals(tvRight))
  			{
  				if(debugline++<10)
  				{
  					LOG.info("###termok###"+String.valueOf(tvleft)+">>>>"+String.valueOf(tvRight)+","+fieldLeft+","+fieldRigth);
  				}
  
  				if(tvleft!=null&&!tvleft.trim().isEmpty())
  				{
  					IntArr LeftArr=this.getListArr(teLeft, tdleft, docs, freqs,Integer.MAX_VALUE);
  					IntArr RightArr=this.getListArr(teRight, tdRight, docs, freqs,1);
  	
  					for (Integer docid:RightArr.list) {
  						HashSet<Integer> list=join_tmp.get(docid);
  						if(list==null)
  						{
  							list=new HashSet<Integer>();
  							join_tmp.put(docid, list);
  						}
  						for(int jid:LeftArr.list)
  						{
  	//						joinRevert_tmp.put(jid, docid);
  							this.joinRevert[jid]=docid;
  							list.add(jid);
  						}
  					}
  				}else{
  					LOG.info("###empty###"+String.valueOf(tvleft)+">>>>"+String.valueOf(tvRight)+","+fieldLeft+","+fieldRigth);
  				}
  				
  				
  				teLeft.next();
  				teRight.next();
  			}else if(tvleft.compareTo(tvRight)>0)
  			{
  				teRight.next();
  			}else{
  				teLeft.next();
  			}
  		}
  		
  		teLeft.close();
  		teRight.close();
  				
  		for(Entry<Integer, HashSet<Integer>> e:join_tmp.entrySet())
  		{
  			this.join[e.getKey()]=IntArr.parse(e.getValue()).list;
  		}
  		join_tmp=null;
  		
  		LOG.info("###join###"+join.length+","+joinRevert.length);
  	}
  		
  }
  