Skip to content
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

Performance improvements #18

Merged
merged 2 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.feature.FeatureCollection;
import com.vividsolutions.jump.feature.FeatureDataset;

/**
* Composes several FeatureMatchers into one. Candidate features are whittled
Expand Down Expand Up @@ -68,8 +69,7 @@ public ChainMatcher(FeatureMatcher[] matchers) {
*/
@Override
public Matches match(Feature target, FeatureCollection candidates) {
Matches survivors = new Matches(
candidates.getFeatureSchema(), candidates.getFeatures());
Matches survivors = new Matches(new FeatureDataset(candidates.getFeatures(), candidates.getFeatureSchema(), candidates.getEnvelope()));
for (FeatureMatcher matcher : matchers) {
survivors = matcher.match(target, survivors);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.vividsolutions.jcs.conflate.polygonmatch;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;

import com.vividsolutions.jump.feature.Feature;
Expand All @@ -24,20 +27,26 @@ public Map<Feature, Matches> match(
FeatureCollection targetFC,
FeatureCollection candidateFC,
TaskMonitor monitor) {
List<Feature> targets = new ArrayList<>();
List<Feature> candidates = new ArrayList<>();
List<Double> scores = new ArrayList<>();
SortedSet<DisambiguationMatch> matchSet = DisambiguationMatch.createDisambiguationMatches(matchFinder.match(targetFC, candidateFC, monitor), monitor);
final SortedSet<DisambiguationMatch> matchSet =
DisambiguationMatch.createDisambiguationMatches(matchFinder.match(targetFC, candidateFC, monitor), monitor);
final List<Feature> targets = new ArrayList<>(matchSet.size());
final List<Feature> candidates = new ArrayList<>(matchSet.size());
// These sets are here to avoid expensive ArrayList#contains calls
final Set<Feature> candidatesSet = new HashSet<>(matchSet.size());
final Set<Feature> targetsSet = new HashSet<>(matchSet.size());
final List<Double> scores = new ArrayList<>(matchSet.size());
monitor.report("Discarding inferior matches");
int j = 0;
for (DisambiguationMatch match : matchSet) {
monitor.report(++j, matchSet.size(), "matches");
if (targets.contains(match.getTarget()) || candidates.contains(match.getCandidate())) {
if (targetsSet.contains(match.getTarget()) || candidatesSet.contains(match.getCandidate())) {
continue;
}
targets.add(match.getTarget());
targetsSet.add(match.getTarget());
candidates.add(match.getCandidate());
scores.add(Double.valueOf(match.getScore()));
candidatesSet.add(match.getCandidate());
scores.add(match.getScore());
}
//Re-add filtered-out targets, but with zero-score matches [Jon Aquino]
Map<Feature, Matches> targetToMatchesMap =
Expand All @@ -46,7 +55,7 @@ public Map<Feature, Matches> match(
candidateFC.getFeatureSchema());
for (int i = 0; i < targets.size(); i++) {
Matches matches = new Matches(candidateFC.getFeatureSchema());
matches.add(candidates.get(i), scores.get(i).doubleValue());
matches.add(candidates.get(i), scores.get(i));
targetToMatchesMap.put(targets.get(i), matches);
}
return targetToMatchesMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ public interface FeatureMatcher {
* @return the matching features, and a score for each. (Implementors should
* document how they do their scoring).
*/
public Matches match(Feature target, FeatureCollection candidates);
Matches match(Feature target, FeatureCollection candidates);

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@
*/
package com.vividsolutions.jcs.conflate.polygonmatch;

import java.util.Collections;

import org.locationtech.jts.geom.Geometry;
import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.feature.FeatureCollection;
import com.vividsolutions.jump.feature.FeatureDataset;

/**
* Base class of FeatureMatchers that compare the target to each candidate
Expand All @@ -46,7 +49,9 @@ public IndependentCandidateMatcher() {

@Override
public Matches match(Feature target, FeatureCollection candidates) {
Matches matches = new Matches(candidates.getFeatureSchema());
final FeatureDataset fds = new FeatureDataset(Collections.emptySet(), candidates.getFeatureSchema(),
candidates.getEnvelope());
final Matches matches = new Matches(fds);
for (Feature candidate : candidates) {
double score = match(target.getGeometry(), candidate.getGeometry());
if (score > 0) { matches.add(candidate, score); }
Expand Down
91 changes: 65 additions & 26 deletions src/com/vividsolutions/jcs/conflate/polygonmatch/Matches.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,18 @@
package com.vividsolutions.jcs.conflate.polygonmatch;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.util.Assert;
import org.locationtech.jts.util.AssertionFailedException;

import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.feature.FeatureCollection;
import com.vividsolutions.jump.feature.FeatureDataset;
Expand All @@ -53,13 +55,14 @@
*/
public class Matches extends AbstractMap<Feature, Double> implements FeatureCollection, Cloneable {
private final Set<Map.Entry<Feature, Double>> entrySet = new HashSet<>();
private int size;
/**
* Creates a Matches object.
* @param schema metadata applicable to the features that will be stored in
* this Matches object
*/
public Matches(FeatureSchema schema) {
dataset = new FeatureDataset(schema);
this(schema, Collections.emptyList());
}

@Override
Expand All @@ -78,14 +81,28 @@ protected Matches clone() {
* @param features added to the Matches, each with the max score (1.0)
*/
public Matches(FeatureSchema schema, List<Feature> features) {
this(schema);
for (Feature match : features) {
add(match, 1);
}
// We want to ensure that the dataset won't have a ton of ArrayList#grow calls
// So we initialize the dataset with all the data
this.dataset = new FeatureDataset(features.size(), schema, null);
this.scores = new double[features.size()];
addAll(features, 1, true);
}

/**
* Creates a Matches object, initialized with the given Dataset.
* @param featureDataset The dataset to use for initialization
*/
public Matches(FeatureDataset featureDataset) {
// We want to ensure that the dataset won't have a ton of ArrayList#grow calls
// So we initialize the dataset with all the data
this.scores = new double[featureDataset.size()];
this.dataset = new FeatureDataset(featureDataset);

addAll(featureDataset, 1, false);
}

private final FeatureDataset dataset;
private final List<Double> scores = new ArrayList<>();
private double[] scores;

/**
* This method is not supported, because added features need to be associated
Expand All @@ -94,7 +111,7 @@ public Matches(FeatureSchema schema, List<Feature> features) {
* @see #add(Feature, double)
*/
@Override
public void add(Feature feature) {
public void add(Feature feature) {
throw new UnsupportedOperationException("Use #add(feature, score) instead");
}

Expand All @@ -103,10 +120,16 @@ public void add(Feature feature) {
* with a score. Use #add(Feature, double) instead.
*/
@Override
public void addAll(Collection<? extends Feature> features) {
public void addAll(Collection<? extends Feature> features) {
throw new UnsupportedOperationException("Use #add(feature, score) instead");
}

private void addAll(Iterable<? extends Feature> features, double score, boolean addToDataset) {
for (Feature feature : features) {
add(feature, score, addToDataset);
}
}

/**
* This method is not supported, because added features need to be associated
* with a score. Use #add(Feature, double) instead.
Expand All @@ -122,7 +145,7 @@ public void add(int index, Feature feature) {
* have matches removed.
*/
@Override
public Collection<Feature> remove(Envelope envelope) {
public Collection<Feature> remove(Envelope envelope) {
//If we decide to implement this, remember to remove the corresponding
//score. [Jon Aquino]
throw new UnsupportedOperationException();
Expand All @@ -133,7 +156,7 @@ public Collection<Feature> remove(Envelope envelope) {
* have matches removed.
*/
@Override
public void clear() {
public void clear() {
//If we decide to implement this, remember to remove the corresponding
//score. [Jon Aquino]
throw new UnsupportedOperationException();
Expand Down Expand Up @@ -162,7 +185,7 @@ private synchronized Set<Entry<Feature, Double>> updateEntrySet() {
* have matches removed.
*/
@Override
public void removeAll(Collection<Feature> features) {
public void removeAll(Collection<Feature> features) {
//If we decide to implement this, remember to remove the corresponding
//score. [Jon Aquino]
throw new UnsupportedOperationException();
Expand All @@ -174,7 +197,7 @@ public void removeAll(Collection<Feature> features) {
* @param feature a feature to remove
*/
@Override
public void remove(Feature feature) {
public void remove(Feature feature) {
//If we decide to implement this, remember to remove the corresponding
//score. [Jon Aquino]
throw new UnsupportedOperationException();
Expand All @@ -185,20 +208,36 @@ public void remove(Feature feature) {
* @param score the confidence of the match, ranging from 0 to 1
*/
public void add(Feature feature, double score) {
Assert.isTrue(0 <= score && score <= 1, "Score = " + score);
add(feature, score, true);
}

private void add(Feature feature, double score, boolean addToDataset) {
// We want to avoid the string concatenation here, if we don't need it.
// It is *very* expensive when run with large datasets.
// This used to be an Assert.isTrue statement
if (0 > score || score > 1) {
throw new AssertionFailedException("Score = " + score);
}
if (score == 0) {
return;
}
scores.add(score);
dataset.add(feature);
scoreAdd(size++, score);
if (addToDataset) dataset.add(feature);
if (score > topScore) {
topScore = score;
topMatch = feature;
}
}

private void scoreAdd(int index, double score) {
if (this.scores.length < index + 1) {
this.scores = Arrays.copyOf(this.scores, index + 1);
}
this.scores[index] = score;
}

private Feature topMatch;
private double topScore = 0;
private double topScore;

public double getTopScore() {
return topScore;
Expand All @@ -217,26 +256,26 @@ public Feature getTopMatch() {
* @return the confidence of the ith match
*/
public double getScore(int i) {
return scores.get(i);
return scores[i];
}

@Override
public FeatureSchema getFeatureSchema() {
public FeatureSchema getFeatureSchema() {
return dataset.getFeatureSchema();
}

@Override
public Envelope getEnvelope() {
public Envelope getEnvelope() {
return dataset.getEnvelope();
}

@Override
public int size() {
public int size() {
return dataset.size();
}

@Override
public boolean isEmpty() {
public boolean isEmpty() {
return dataset.isEmpty();
}

Expand All @@ -245,17 +284,17 @@ public Feature getFeature(int index) {
}

@Override
public List<Feature> getFeatures() {
public List<Feature> getFeatures() {
return dataset.getFeatures();
}

@Override
public Iterator<Feature> iterator() {
public Iterator<Feature> iterator() {
return dataset.iterator();
}

@Override
public List<Feature> query(Envelope envelope) {
public List<Feature> query(Envelope envelope) {
return dataset.query(envelope);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.locationtech.jts.geom.Envelope;
import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.feature.FeatureCollection;
import com.vividsolutions.jump.feature.FeatureDataset;
import com.vividsolutions.jump.geom.EnvelopeUtil;

/**
Expand Down Expand Up @@ -79,6 +80,6 @@ public WindowMatcher() {}
public Matches match(Feature target, FeatureCollection candidates) {
Envelope window = new Envelope(target.getGeometry().getEnvelopeInternal());
window = EnvelopeUtil.expand(window, buffer);
return new Matches(candidates.getFeatureSchema(), candidates.query(window));
return new Matches(new FeatureDataset(candidates.query(window), candidates.getFeatureSchema(), window));
}
}
Loading
Loading