-
Notifications
You must be signed in to change notification settings - Fork 18
Extend Filters, extract Ids #509
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
16928ca
514a5cc
b642123
4a9580a
6d83b24
4529e56
bb87c50
9284e1a
e335a4b
bdb936b
d2df862
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package org.heigit.ohsome.oshdb.filter; | ||
|
||
import org.heigit.ohsome.oshdb.OSHDBTag; | ||
import org.heigit.ohsome.oshdb.osm.OSMType; | ||
|
||
import java.util.*; | ||
import java.util.function.Function; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Stream; | ||
|
||
import static java.util.Collections.*; | ||
import static java.util.Comparator.comparingLong; | ||
|
||
public class FilterUtil { | ||
|
||
private FilterUtil() { | ||
throw new IllegalStateException("utility class"); | ||
} | ||
|
||
public static Map<EnumSet<OSMType>, Set<OSHDBTag>> tags(FilterExpression expression, Predicate<OSHDBTag> test) { | ||
return tags(expression.normalize(), test); | ||
} | ||
|
||
public static Map<EnumSet<OSMType>, Set<OSHDBTag>> tags(List<List<Filter>> normalized, Predicate<OSHDBTag> test) { | ||
return extract(normalized, filter -> { | ||
if (filter instanceof TagFilterEquals tagFilter) { | ||
return Stream.of(tagFilter.getTag()).filter(test); | ||
} else if (filter instanceof TagFilterEqualsAny tagFilter) { | ||
return Stream.of(tagFilter.getTag()).map(key -> new OSHDBTag(key.toInt(), -1)).filter(test); | ||
} else if (filter instanceof TagFilterEqualsAnyOf tagFilter) { | ||
return tagFilter.tags.stream().filter(test); | ||
} | ||
return Stream.empty(); | ||
}); | ||
} | ||
|
||
private static <T> Map<EnumSet<OSMType>, Set<T>> extract(List<List<Filter>> normalized, Function<Filter, Stream<T>> extractor) { | ||
var result = new HashMap<EnumSet<OSMType>, Set<T>>(); | ||
for(var group: normalized){ | ||
var type = EnumSet.allOf(OSMType.class); | ||
var groupResult = new HashSet<T>(); | ||
for (var filter : group) { | ||
if (filter instanceof TypeFilter typeFilter) { | ||
type = EnumSet.of(typeFilter.getType()); | ||
} else { | ||
extractor.apply(filter).forEach(groupResult::add); | ||
} | ||
} | ||
if (groupResult.isEmpty()) { | ||
return emptyMap(); | ||
} | ||
result.computeIfAbsent(type, x -> new HashSet<>()).addAll(groupResult); | ||
} | ||
return result; | ||
} | ||
|
||
public static Map<EnumSet<OSMType>, Set<IdRange>> extractIds(FilterExpression expression) { | ||
return extractIds(expression.normalize()); | ||
} | ||
|
||
public static Map<EnumSet<OSMType>, Set<IdRange>> extractIds(List<List<Filter>> normalized) { | ||
var result = extract(normalized, filter -> { | ||
if (filter instanceof IdFilterEquals idFilter){ | ||
return Stream.of(new IdRange(idFilter.getId())); | ||
} else if (filter instanceof IdFilterEqualsAnyOf idFilter) { | ||
return idFilter.getIds().stream().map(IdRange::new); | ||
} else if (filter instanceof IdFilterRange idFilter) { | ||
return Stream.of(idFilter.getRange()); | ||
} | ||
return Stream.empty(); | ||
}); | ||
compactRanges(result); | ||
return result; | ||
} | ||
|
||
private static void compactRanges(Map<EnumSet<OSMType>, Set<IdRange>> result) { | ||
for (var entry : result.entrySet()) { | ||
var ranges = new ArrayList<>(entry.getValue()); | ||
var compact = new HashSet<IdRange>(ranges.size()); | ||
ranges.sort(comparingLong(IdRange::getFromId)); | ||
var itr = ranges.iterator(); | ||
var range = itr.next(); | ||
while (itr.hasNext()) { | ||
var next = itr.next(); | ||
if (next.getFromId() <= range.getToId() + 1) { | ||
range = new IdRange(range.getFromId(), next.getToId()); | ||
} else { | ||
compact.add(range); | ||
range = next; | ||
} | ||
} | ||
compact.add(range); | ||
entry.setValue(compact); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could move the code from public static Set<OSMType> extractTypes(FilterExpression expression) {
return extractTypes(expression.normalize());
}
public static Set<OSMType> extractTypes(List<List<Filter>> normalized) {
var allTypes = EnumSet.noneOf(OSMType.class);
extract(normalized, ignored -> Stream.of(true)).keySet()
.forEach(allTypes::addAll);
return allTypes;
} and in mapRed = mapRed.osmTypeInternal(FilterUtil.extractTypes(filter)); |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,13 +12,19 @@ | |
* A tag filter which executes a "id [not] in (id1, id2, …)" check. | ||
*/ | ||
public class IdFilterEqualsAnyOf extends NegatableFilter { | ||
|
||
private final Set<Long> ids; | ||
|
||
IdFilterEqualsAnyOf(@Nonnull Collection<Long> idList) { | ||
this(new HashSet<>(idList)); | ||
} | ||
|
||
IdFilterEqualsAnyOf(@Nonnull Set<Long> ids) { | ||
super(new FilterInternal() { | ||
private final Set<Long> ids = new HashSet<>(idList); | ||
|
||
@Override | ||
public boolean applyOSH(OSHEntity entity) { | ||
return this.ids.contains(entity.getId()); | ||
return ids.contains(entity.getId()); | ||
} | ||
|
||
@Override | ||
|
@@ -28,7 +34,7 @@ boolean applyOSHNegated(OSHEntity entity) { | |
|
||
@Override | ||
public boolean applyOSM(OSMEntity entity) { | ||
return this.ids.contains(entity.getId()); | ||
return ids.contains(entity.getId()); | ||
} | ||
|
||
@Override | ||
|
@@ -38,12 +44,18 @@ boolean applyOSMNegated(OSMEntity entity) { | |
|
||
@Override | ||
public String toString() { | ||
return "id:in" + this.ids.stream().map(String::valueOf).collect(Collectors.joining(",")); | ||
return "id:in" + ids.stream().map(String::valueOf).collect(Collectors.joining(",")); | ||
} | ||
}); | ||
|
||
if (idList.isEmpty()) { | ||
if (ids.isEmpty()) { | ||
throw new IllegalStateException("list of ids must not be empty in a id in (list) filter"); | ||
} | ||
|
||
this.ids = ids; | ||
} | ||
|
||
public Set<Long> getIds() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this could be included in |
||
return ids; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is missing a case:
GeometryTypeFilter
s do implicitly also filter by type (e.g.geometry: polygon
is equivalent to something like(type:way or (type:relation and type=multipolygon)) and <actual geometry check>
.Something like this should work:
Another question is if there are cases where we want the
extractor
to be called withGeometryTypeFilter
s. 🤔