package org.apache.solr.request.mdrill; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.zip.CRC32; import org.apache.lucene.document.Document; import org.apache.lucene.document.Fieldable; import org.apache.lucene.document.MapFieldSelector; import org.apache.lucene.index.SegmentReader; import org.apache.lucene.queryParser.ParseException; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.schema.FieldType; import org.apache.solr.schema.IndexSchema; import org.apache.solr.search.DocIterator; import org.apache.solr.search.DocSet; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.compare.ColumnKey; import org.apache.solr.request.compare.RecordCountDetail; import org.apache.solr.request.compare.SelectDetailRow; import org.apache.solr.request.compare.ShardDetailSelectDetailRowStringCompare; import com.alimama.mdrill.utils.EncodeUtils; import com.alimama.mdrill.utils.UniqConfig; /** 查询明细的实现-无排序,无join * @author yannian.mu */ public class MdrillDetailFdt { private SolrIndexSearcher searcher; private RecordCountDetail recordCount ; private SolrQueryRequest req; private MdrillParseDetailFdt parse; private SegmentReader reader; private MdrillParseDetailFdt.fetchContaioner container=null; String crcget=null; String segKey=null; private String hostId=java.util.UUID.randomUUID().toString(); SolrParams params; public MdrillDetailFdt(SolrIndexSearcher _searcher,SegmentReader reader,SolrParams _params,SolrQueryRequest req) { try { this.hostId=java.net.InetAddress.getLocalHost().getHostAddress()+","+String.valueOf(java.net.InetAddress.getLocalHost().getHostName()); } catch (UnknownHostException e) { hostId=java.util.UUID.randomUUID().toString(); } this.segKey=reader.getSigmentUniqKey(); this.reader=reader; this.req=req; this.searcher=_searcher; this.parse=new MdrillParseDetailFdt(_params); this.crcget=_params.get("mdrill.crc.key.get",null); this.recordCount = new RecordCountDetail(); this.params=_params; } public static class Doclist{ public int[] list; public Doclist(int size) { super(); this.list = new int[size]; } public void add(int doc) { list[index]=doc; this.index++; } public int index=0; } public NamedList get(String[] fields, DocSet baseDocs) throws IOException, ParseException { if(this.crcget==null) { this.container=this.parse.createContainer(fields, baseDocs, this.reader, this.searcher, this.req); DocIterator iter = baseDocs.iterator(); this.recordCount.inc(baseDocs.size()); Doclist res=new Doclist(this.parse.limit_offset); int doc=-1; while (iter.hasNext()) { doc = iter.nextDoc(); res.add(doc); if(res.index>=this.parse.limit_offset) { break; } } PriorityQueue<SelectDetailRow> topItems=this.transGroupValue(res,fields); this.container.free(); return this.toNameList(topItems); } String hostkey=String.valueOf(this.getkeyCrc()); ConcurrentHashMap<Long,String> cache=MdrillUtils.CRC_CACHE_SIZE.remove(crcget+"@"+hostkey); NamedList rtn=new NamedList(); Map<Long,String> crcvalue=new HashMap<Long,String>(); rtn.add("fdtcre", crcvalue); if(cache!=null) { MapFieldSelector selector=new MapFieldSelector(fields); FieldType[] ftlist=new FieldType[fields.length]; IndexSchema schema=this.searcher.getSchema(); for (int j = 0; j < fields.length; j++) { ftlist[j]=schema.getFieldType(fields[j]); } String crcliststr=params.get("mdrill.crc.key.get.crclist"); if(crcliststr!=null) { String[] crclist=crcliststr.split(","); for(String s:crclist) { Long crc=Long.parseLong(s); String v=cache.get(crc); if(v!=null) { String cols[]=v.split(UniqConfig.GroupJoinString(),-1); if(cols.length>=2) { int doc=Integer.parseInt(cols[0]); SortGroupVal buff = new SortGroupVal(); buff.groupbuff.append("-"); buff.groupbuff.append(UniqConfig.GroupJoinString()); buff.groupbuff.append("-"); Document docfields=this.reader.document(doc,selector); if(docfields==null) { for (int j = 0; j < fields.length; j++) { buff.groupbuff.append(UniqConfig.GroupJoinString()); buff.groupbuff.append(EncodeUtils.encode("-")); } if(!crcvalue.containsKey(crc)) { crcvalue.put(crc, buff.groupbuff.toString()); } }else{ for (int j = 0; j < fields.length; j++) { buff.groupbuff.append(UniqConfig.GroupJoinString()); Fieldable fv=docfields.getFieldable(fields[j]); if(fv!=null) { buff.groupbuff.append(EncodeUtils.encode(ftlist[j].toExternal(fv))); } else{ buff.groupbuff.append(EncodeUtils.encode("-")); } } crcvalue.put(crc, buff.groupbuff.toString()); } } } } } } return rtn; } private long getkeyCrc() { CRC32 crc32 = new CRC32(); crc32.update(String.valueOf(hostId+"@"+this.segKey).getBytes()); return crc32.getValue(); } public PriorityQueue<SelectDetailRow> transGroupValue(Doclist res,String[] fields)throws ParseException, IOException { long key=getkeyCrc(); PriorityQueue<SelectDetailRow> topItems = new PriorityQueue<SelectDetailRow>(this.parse.limit_offset, Collections.reverseOrder(defcmp)); for(int i=0;i<res.index;i++) { int doc = res.list[i]; SortGroupVal buff = new SortGroupVal(); buff.groupbuff.append(String.valueOf(doc)); buff.groupbuff.append(UniqConfig.GroupJoinString()); buff.groupbuff.append(String.valueOf(key)); for (int j = 0; j < fields.length; j++) { buff.groupbuff.append(UniqConfig.GroupJoinString()); buff.groupbuff.append(EncodeUtils.encode("-")); } buff.sortString="0"; SelectDetailRow newrow = SelectDetailRow.INSTANCE(doc, doc); newrow.setKey(new ColumnKey(buff.groupbuff.toString())); newrow.colVal=buff.sortString; QueuePutUtils.put2QueueDetail(newrow, topItems, this.parse.limit_offset,defcmp); } return topItems; } private ShardDetailSelectDetailRowStringCompare defcmp=new ShardDetailSelectDetailRowStringCompare("string", true); private NamedList toNameList(PriorityQueue<SelectDetailRow> topItems) { java.util.ArrayList<SelectDetailRow> recommendations = new ArrayList<SelectDetailRow>(topItems.size()); recommendations.addAll(topItems); Collections.sort(recommendations,defcmp); Integer index = 0; NamedList res = new NamedList(); res.add("count", recordCount.toNamedList()); ConcurrentHashMap<Long,String> cache=null; boolean issetCrc=this.parse.crcOutputSet!=null; long crckey=this.getkeyCrc(); if(issetCrc) { synchronized (MdrillUtils.CRC_CACHE_SIZE) { cache=MdrillUtils.CRC_CACHE_SIZE.get(this.parse.crcOutputSet+"@"+crckey); if(cache==null) { cache=new ConcurrentHashMap<Long,String>(); MdrillUtils.CRC_CACHE_SIZE.put(this.parse.crcOutputSet+"@"+crckey, cache); } } } ArrayList<Object> list=new ArrayList<Object>(); for (SelectDetailRow kv : recommendations) { if (index >= this.parse.offset) { if(issetCrc) { kv.ToCrcSet(cache); } list.add(kv.toNamedList()); } index++; } res.add("list", list); return res; } public static class SortGroupVal{ public StringBuffer groupbuff=new StringBuffer(); public String sortString; } }