org.apache.lucene.queries.intervals.OrderedIntervalsSource Maven / Gradle / Ivy
The newest version!
/*
* 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.lucene.queries.intervals;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
class OrderedIntervalsSource extends MinimizingConjunctionIntervalsSource {
static IntervalsSource build(List sources) {
if (sources.size() == 1) {
return sources.get(0);
}
List rewritten = deduplicate(flatten(sources));
if (rewritten.size() == 1) {
return rewritten.get(0);
}
return new OrderedIntervalsSource(rewritten);
}
private static List flatten(List sources) {
List flattened = new ArrayList<>();
for (IntervalsSource s : sources) {
if (s instanceof OrderedIntervalsSource) {
flattened.addAll(((OrderedIntervalsSource) s).subSources);
} else {
flattened.add(s);
}
}
return flattened;
}
private static List deduplicate(List sources) {
List deduplicated = new ArrayList<>();
List current = new ArrayList<>();
for (IntervalsSource source : sources) {
if (current.size() == 0 || current.get(0).equals(source)) {
current.add(source);
} else {
deduplicated.add(RepeatingIntervalsSource.build(current.get(0), current.size()));
current.clear();
current.add(source);
}
}
deduplicated.add(RepeatingIntervalsSource.build(current.get(0), current.size()));
if (deduplicated.size() == 1 && deduplicated.get(0) instanceof RepeatingIntervalsSource) {
((RepeatingIntervalsSource) deduplicated.get(0)).setName("ORDERED");
}
return deduplicated;
}
private OrderedIntervalsSource(List sources) {
super(sources);
}
@Override
protected IntervalIterator combine(List iterators, MatchCallback onMatch) {
return new OrderedIntervalIterator(iterators, onMatch);
}
@Override
public int minExtent() {
int minExtent = 0;
for (IntervalsSource subSource : subSources) {
minExtent += subSource.minExtent();
}
return minExtent;
}
@Override
public Collection pullUpDisjunctions() {
return Disjunctions.pullUp(subSources, OrderedIntervalsSource::new);
}
@Override
public int hashCode() {
return Objects.hashCode(subSources);
}
@Override
public boolean equals(Object other) {
if (other instanceof OrderedIntervalsSource == false) return false;
OrderedIntervalsSource s = (OrderedIntervalsSource) other;
return Objects.equals(subSources, s.subSources);
}
@Override
public String toString() {
return "ORDERED("
+ subSources.stream().map(IntervalsSource::toString).collect(Collectors.joining(","))
+ ")";
}
private static class OrderedIntervalIterator extends ConjunctionIntervalIterator {
int start = -1, end = -1, i = 1;
int slop;
final MatchCallback onMatch;
private OrderedIntervalIterator(List subIntervals, MatchCallback onMatch) {
super(subIntervals);
this.onMatch = onMatch;
}
@Override
public int start() {
return start;
}
@Override
public int end() {
return end;
}
@Override
public int nextInterval() throws IOException {
start = end = slop = IntervalIterator.NO_MORE_INTERVALS;
int lastStart = Integer.MAX_VALUE;
boolean minimizing = false;
while (true) {
while (true) {
if (subIterators.get(i - 1).end() >= lastStart) {
return start;
}
if (i == subIterators.size()
|| (minimizing && subIterators.get(i).start() > subIterators.get(i - 1).end())) {
break;
}
do {
if (subIterators.get(i).end() >= lastStart
|| subIterators.get(i).nextInterval() == IntervalIterator.NO_MORE_INTERVALS) {
return start;
}
} while (subIterators.get(i).start() <= subIterators.get(i - 1).end());
i++;
}
start = subIterators.get(0).start();
if (start == NO_MORE_INTERVALS) {
return end = NO_MORE_INTERVALS;
}
end = subIterators.get(subIterators.size() - 1).end();
slop = end - start + 1;
for (IntervalIterator subIterator : subIterators) {
slop -= subIterator.width();
}
onMatch.onMatch();
lastStart = subIterators.get(subIterators.size() - 1).start();
i = 1;
if (subIterators.get(0).nextInterval() == IntervalIterator.NO_MORE_INTERVALS) {
return start;
}
minimizing = true;
}
}
@Override
public int gaps() {
return slop;
}
@Override
protected void reset() throws IOException {
subIterators.get(0).nextInterval();
i = 1;
start = end = slop = -1;
}
}
}