/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.analytics.accumulator.facet;
import java.io.IOException;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.util.BytesRef;
import org.apache.solr.analytics.accumulator.FacetingAccumulator;
import org.apache.solr.analytics.accumulator.ValueAccumulator;
import org.apache.solr.analytics.util.AnalyticsParsers.NumericParser;
import org.apache.solr.analytics.util.AnalyticsParsers.Parser;
import org.apache.solr.analytics.util.AnalyticsParsers;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.schema.DateValueFieldType;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.SolrIndexSearcher;
/**
* An Accumulator that manages the faceting for fieldFacets.
* Collects the field facet values.
*/
public class FieldFacetAccumulator extends ValueAccumulator {
protected final Parser parser;
protected final FacetValueAccumulator parent;
protected final String name;
protected final SolrIndexSearcher searcher;
protected final SchemaField schemaField;
protected final boolean multiValued;
protected final boolean numField;
protected final boolean dateField;
protected SortedSetDocValues setValues;
protected SortedDocValues sortValues;
protected NumericDocValues numValues;
public FieldFacetAccumulator(SolrIndexSearcher searcher, FacetValueAccumulator parent, SchemaField schemaField) throws IOException {
if( !schemaField.hasDocValues() ){
throw new IOException("Field '"+schemaField.getName()+"' does not have docValues and therefore cannot be faceted over.");
}
this.searcher = searcher;
this.schemaField = schemaField;
this.name = schemaField.getName();
this.multiValued = schemaField.multiValued();
this.numField = schemaField.getType().getNumberType()!=null;
this.dateField = schemaField.getType() instanceof DateValueFieldType;
this.parent = parent;
this.parser = AnalyticsParsers.getParser(schemaField.getType().getClass());
}
public static FieldFacetAccumulator create(SolrIndexSearcher searcher, FacetValueAccumulator parent, SchemaField facetField) throws IOException{
return new FieldFacetAccumulator(searcher,parent,facetField);
}
/**
* Move to the next set of documents to add to the field facet.
*/
@Override
protected void doSetNextReader(LeafReaderContext context) throws IOException {
if (multiValued) {
setValues = context.reader().getSortedSetDocValues(name);
} else {
if (numField) {
numValues = context.reader().getNumericDocValues(name);
} else {
sortValues = context.reader().getSortedDocValues(name);
}
}
}
/**
* Tell the FacetingAccumulator to collect the doc with the
* given fieldFacet and value(s).
*/
@Override
public void collect(int doc) throws IOException {
if (multiValued) {
boolean exists = false;
if (setValues!=null) {
if (doc > setValues.docID()) {
setValues.advance(doc);
}
if (doc == setValues.docID()) {
int term;
while ((term = (int)setValues.nextOrd()) != SortedSetDocValues.NO_MORE_ORDS) {
exists = true;
final BytesRef value = setValues.lookupOrd(term);
parent.collectField(doc, name, parser.parse(value) );
}
}
}
if (!exists) {
parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
}
} else {
if(numField){
if(numValues != null) {
int valuesDocID = numValues.docID();
if (valuesDocID < doc) {
valuesDocID = numValues.advance(doc);
}
if (valuesDocID == doc) {
parent.collectField(doc, name, ((NumericParser)parser).parseNum(numValues.longValue()));
} else {
parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
}
} else {
parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
}
} else {
if(sortValues != null) {
if (doc > sortValues.docID()) {
sortValues.advance(doc);
}
if (doc == sortValues.docID()) {
parent.collectField(doc, name, parser.parse(sortValues.lookupOrd(sortValues.ordValue())) );
} else {
parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
}
} else {
parent.collectField(doc, name, FacetingAccumulator.MISSING_VALUE );
}
}
}
}
@Override
public void compute() {}
@Override
public NamedList<?> export() { return null; }
@Override
public boolean needsScores() {
return true; // TODO: is this true?
}
}