/* * 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.search.facet; import java.io.IOException; import org.apache.lucene.index.DocValues; import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.util.BytesRef; import org.apache.solr.schema.SchemaField; import org.apache.solr.search.QParser; import org.apache.solr.search.QueryContext; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.uninverting.FieldCacheImpl; /** @lucene.internal * Porting helper... may be removed if it offers no value in the future. */ public class FieldUtil { /** Simpler method that creates a request context and looks up the field for you */ public static SortedDocValues getSortedDocValues(SolrIndexSearcher searcher, String field) throws IOException { SchemaField sf = searcher.getSchema().getField(field); QueryContext qContext = QueryContext.newContext(searcher); return getSortedDocValues( qContext, sf, null ); } public static SortedDocValues getSortedDocValues(QueryContext context, SchemaField field, QParser qparser) throws IOException { SortedDocValues si = context.searcher().getSlowAtomicReader().getSortedDocValues( field.getName() ); // if (!field.hasDocValues() && (field.getType() instanceof StrField || field.getType() instanceof TextField)) { // } return si == null ? DocValues.emptySorted() : si; } public static SortedSetDocValues getSortedSetDocValues(QueryContext context, SchemaField field, QParser qparser) throws IOException { SortedSetDocValues si = context.searcher().getSlowAtomicReader().getSortedSetDocValues(field.getName()); return si == null ? DocValues.emptySortedSet() : si; } /** The following ord visitors and wrappers are a work in progress and experimental * @lucene.experimental */ @FunctionalInterface public interface OrdFunc { void handleOrd(int docid, int ord); // TODO: throw exception? } public static boolean isFieldCache(SortedDocValues singleDv) { return singleDv instanceof FieldCacheImpl.SortedDocValuesImpl.Iter; } public static void visitOrds(SortedDocValues singleDv, DocIdSetIterator disi, OrdFunc ordFunc) throws IOException { int doc; if (singleDv instanceof FieldCacheImpl.SortedDocValuesImpl.Iter) { FieldCacheImpl.SortedDocValuesImpl.Iter fc = (FieldCacheImpl.SortedDocValuesImpl.Iter) singleDv; while ((doc = disi.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) { ordFunc.handleOrd(doc, fc.getOrd(doc)); } } else { while ((doc = disi.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) { if (singleDv.advanceExact(doc)) { ordFunc.handleOrd(doc, singleDv.ordValue()); } else { // TODO: optionally pass in missingOrd? } } } } public static OrdValues getOrdValues(SortedDocValues singleDv, DocIdSetIterator disi) { if (singleDv instanceof FieldCacheImpl.SortedDocValuesImpl.Iter) { FieldCacheImpl.SortedDocValuesImpl.Iter fc = (FieldCacheImpl.SortedDocValuesImpl.Iter) singleDv; return new FCOrdValues(fc, disi); } return new DVOrdValues(singleDv, disi); } public static abstract class OrdValues extends SortedDocValues { int doc; int ord; public int getOrd() { return ord; } @Override public int docID() { return doc; } @Override public abstract int nextDoc() throws IOException; @Override public int advance(int target) throws IOException { return 0; // TODO } @Override public long cost() { return 0; } @Override public int getValueCount() { throw new UnsupportedOperationException(); } } public static class FCOrdValues extends OrdValues { FieldCacheImpl.SortedDocValuesImpl.Iter vals; DocIdSetIterator disi; public FCOrdValues(FieldCacheImpl.SortedDocValuesImpl.Iter iter, DocIdSetIterator disi) { this.vals = iter; this.disi = disi; } @Override public int nextDoc() throws IOException { doc = disi.nextDoc(); if (doc == NO_MORE_DOCS) return NO_MORE_DOCS; ord = vals.getOrd(doc); // todo: loop until a hit? return doc; } @Override public boolean advanceExact(int target) throws IOException { return false; } @Override public int ordValue() { return 0; } @Override public BytesRef lookupOrd(int ord) throws IOException { return null; } } public static class DVOrdValues extends OrdValues { SortedDocValues vals; DocIdSetIterator disi; int valDoc; public DVOrdValues(SortedDocValues vals, DocIdSetIterator disi) { this.vals = vals; this.disi = disi; } @Override public int nextDoc() throws IOException { for (;;) { // todo - use skipping when appropriate doc = disi.nextDoc(); if (doc == NO_MORE_DOCS) return NO_MORE_DOCS; boolean match = vals.advanceExact(doc); if (match) { ord = vals.ordValue(); return doc; } } } @Override public boolean advanceExact(int target) throws IOException { return false; } @Override public int ordValue() { return 0; } @Override public BytesRef lookupOrd(int ord) throws IOException { return null; } } }