- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的应用程序中,有一个用例来查找距其他地理点最近的点。我决定使用内存空间索引并找到了几个候选索引:jeospatial和 Lucene spatial .
我做了一些基准测试,并惊讶地发现 Lucene 索引结果非常慢。这是来自基准测试的代码,它是用 JMH 完成的。完整的源代码可以在我的GitHub repository中找到.
@State(Scope.Thread)
public class MyBenchmark {
// Lucene
private static final String COORDINATES_FIELD = "coordinates";
private static final int GEO_PRECISION_LEVEL = 5;
private static final double NEARBY_RADIUS_DEGREE = DistanceUtils.dist2Degrees(
50, DistanceUtils.EARTH_MEAN_RADIUS_KM);
private final Directory directory = new RAMDirectory();
private final IndexWriterConfig iwConfig = new IndexWriterConfig();
private IndexWriter indexWriter = null;
private IndexSearcher indexSearcher = null;
private final SpatialContext spatialCxt = SpatialContext.GEO;
private final ShapeFactory shapeFactory = spatialCxt.getShapeFactory();
private final SpatialStrategy coordinatesStrategy = new RecursivePrefixTreeStrategy(
new GeohashPrefixTree(spatialCxt, GEO_PRECISION_LEVEL),
COORDINATES_FIELD);
// Jeospatial
private VPTree<SimpleGeospatialPoint> jeospatialPoints = new VPTree<>();
public MyBenchmark() {
try {
indexWriter = new IndexWriter(directory, iwConfig);
} catch (IOException e) {
e.printStackTrace();
}
}
@Setup
public void init() throws IOException {
var r = new Random();
for (int i = 0; i < 3000; i++) {
double latitude = ThreadLocalRandom.current().nextDouble(50.4D, 51.4D);
double longitude = ThreadLocalRandom.current().nextDouble(8.2D, 11.2D);
Document doc = new Document();
doc.add(new StoredField("id", r.nextInt()));
var point = shapeFactory.pointXY(longitude, latitude);
for (var field : coordinatesStrategy.createIndexableFields(point)) {
doc.add(field);
}
doc.add(new StoredField(coordinatesStrategy.getFieldName(), latitude + ":" + longitude));
indexWriter.addDocument(doc);
jeospatialPoints.add(new MyGeospatialPoint(latitude, longitude));
}
indexWriter.forceMerge(1);
indexWriter.close();
final IndexReader indexReader = DirectoryReader.open(directory);
indexSearcher = new IndexSearcher(indexReader);
}
private SimpleGeospatialPoint createRandomPoint() {
final double latitude = ThreadLocalRandom.current().nextDouble(50.4D, 51.4D);
final double longitude = ThreadLocalRandom.current().nextDouble(8.2D, 11.2D);
return new MyGeospatialPoint(latitude, longitude);
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@Fork(value = 1)
@Warmup(iterations = 0)
@Measurement(iterations = 3)
public void benchLucene() {
double latitude = ThreadLocalRandom.current().nextDouble(50.4D, 51.4D);
double longitude = ThreadLocalRandom.current().nextDouble(8.2D, 11.2D);
final var spatialArgs = new SpatialArgs(SpatialOperation.IsWithin,
shapeFactory.circle(longitude, latitude, NEARBY_RADIUS_DEGREE));
final Query q = coordinatesStrategy.makeQuery(spatialArgs);
try {
final TopDocs topDocs = indexSearcher.search(q, 1);
if (topDocs.totalHits == 0) {
return;
}
var doc = indexSearcher.doc(topDocs.scoreDocs[0].doc);
var coordinates = doc.getField(COORDINATES_FIELD).stringValue();
} catch (IOException e) {
e.printStackTrace();
}
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@Fork(value = 1)
@Warmup(iterations = 0)
@Measurement(iterations = 3)
public void benchJeospatial() {
var neighbor = jeospatialPoints.getNearestNeighbor(createRandomPoint(), 50 * 1000);
var n = neighbor.getLatitude();
}
}
在 Lucene 中,我使用 RAMDirectory
,但也尝试过 MMapDirectory
。几乎没有区别。
基准测试结果:
# JMH version: 1.21
# VM version: JDK 10, Java HotSpot(TM) 64-Bit Server VM, 10+46
# VM invoker: /Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home/bin/java
# VM options: <none>
# Warmup: <none>
# Measurement: 3 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.MyBenchmark.benchJeospatial
# Run progress: 0,00% complete, ETA 00:01:00
# Fork: 1 of 1
Iteration 1: 77528,657 ops/s
Iteration 2: 81921,096 ops/s
Iteration 3: 83470,405 ops/s
Result "org.sample.MyBenchmark.benchJeospatial":
80973,386 ±(99.9%) 56230,060 ops/s [Average]
(min, avg, max) = (77528,657, 80973,386, 83470,405), stdev = 3082,159
CI (99.9%): [24743,326, 137203,446] (assumes normal distribution)
# JMH version: 1.21
# VM version: JDK 10, Java HotSpot(TM) 64-Bit Server VM, 10+46
# VM invoker: /Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home/bin/java
# VM options: <none>
# Warmup: <none>
# Measurement: 3 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.MyBenchmark.benchLucene
# Run progress: 50,00% complete, ETA 00:00:31
# Fork: 1 of 1
Iteration 1: 997,103 ops/s
Iteration 2: 1087,487 ops/s
Iteration 3: 1077,964 ops/s
Result "org.sample.MyBenchmark.benchLucene":
1054,184 ±(99.9%) 906,037 ops/s [Average]
(min, avg, max) = (997,103, 1054,184, 1087,487), stdev = 49,663
CI (99.9%): [148,147, 1960,221] (assumes normal distribution)
# Run complete. Total time: 00:01:03
REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.
Benchmark Mode Cnt Score Error Units
MyBenchmark.benchJeospatial thrpt 3 80973,386 ± 56230,060 ops/s
MyBenchmark.benchLucene thrpt 3 1054,184 ± 906,037 ops/s
如您所见,Jeospatial 的速度快了约 75 倍。所以我很好奇,如果这确实是真的,或者我只是以某种方式错误地配置了 Lucene。
最佳答案
注意到这是大约一年前发布的。以下内容现在与当时一样相关,但性能要好得多。
不要使用spatial-extras
,使用LatLonPoint
,它是更高效、更直接的 API。
这就是您所需要的:
// add your points to the document
doc.add(new LatLonPoint(fieldName, lat, lon));
// create your distance query
Query q = LatLonPoint.newDistanceQuery(fieldName, centerLat, centerLon, radiusMeters);
您遇到空间附加(在倒排索引中使用前缀树)性能问题的原因有多种:
GEO_PRECISION_LEVEL
)。shapeFactory.circle
的
makeQuery
并不是真正的距离搜索。通过相同的四叉树分解处理圆,以创建近似圆的项(四元胞)集合。然后使用 JTS.relate
对照圆的栅格检查倒排索引中的项,这是一项极其昂贵的操作。LatLonPoint
创建 block KD 树结构而不是使用倒排索引。它是一种专为大规模空间和多维数字而设计的数据结构。它的空间和时间效率更高,并且在非常大的数据集上表现更好。
希望这有帮助!
关于performance - Lucene 内存空间索引性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52302394/
这几天我一直在努力。我一直在自学 CSS,所以对菜鸟好一点。我正在创建一个推荐 slider 。推荐以 3 个 block 显示。我希望前 2 个下降,第 3 个上升。但是当 slider 激活时,无
我最近开始学习 Nodejs,现在我很困惑我的网络应用程序使用什么,html 还是 ejs (Express)。 Ejs 使用 Express 模块,而 .html 使用 HTML 模块。我的第一个问
假设我们有一个 PostgreSQL 表contacts,每条记录都有一堆带标签的电子邮件地址(标签和电子邮件对)——其中一个是“主要”。 存储方式如下: id 主键 电子邮件 文本 email_la
我成功为一种新的tesseract语言编写了traineddata文件,但是当我完成时,我继续收到以下错误: index >= 0 && index = 0 && 索引 < size_used_ :E
这个问题已经有答案了: How to deal with SettingWithCopyWarning in Pandas (21 个回答) 已关闭 4 年前。 假设我有一个像这样的数据框,第一列“密
如果我有一个位置或行/列同时用于 A 和 B 位置,请检查 B 是否与 A 成对角线? 1 2 3 4 5 6 7 8 9 例如,我如何检查 5 是否与 7 成对角线? 此外,如果我检查 4 是
MongoDB:索引 一、 创建索引 默认情况下,集合中的_id字段就是索引,我们可以通过getIndexes()方法来查看一个集合中的索引 > db.user.getIndexes() [ { "v
一、索引介绍 索引是一种用来快速查询数据的数据结构。 B+Tree就是一种常用的数据库索引数据结构,MongoDB采用B+Tree 做索引,索引创建在colletions上。 MongoDB不使用索引
我无法决定索引。 就像我有下面的查询需要太多时间来执行: select count(rn.NODE_ID) as Count, rnl.[ISO_COUNTRY_CODE] as Cou
我有这些表: CREATE TABLE `cstat` ( `id_cstat` bigint(20) NOT NULL, `lang_code` varchar(3) NOT NULL,
我正在尝试找到一种方法来提高包含 IP 范围的 mysql 表的性能(在高峰时段每秒最多有 500 个 SELECT 查询(!),所以我有点担心)。 我有一个这种结构的表: id smallint(
jquery index() 似乎无法识别元素之一,总是说“无法读取未定义的属性‘长度’”这是我的代码。mnumber 是导致问题的原因。我需要 number 和 mnumber 才能跟踪使用鼠标,并
我们有一个包含近 4000 万条记录的 MongoDB 集合。该集合的当前大小为 5GB。此集合中存储的数据包含以下字段: _id: "MongoDB id" userid: "user id" (i
文档说:如果你有多个字段的复合索引,你可以用它来查询字段的开始子集。所以如果你有一个索引一个,乙,丙你可以用它查询一种一个,乙a,b,c 我的问题是,如果我有一个像这样的复合索引一个,乙,丙我可以查询
我正在使用 $('#list option').each(function(){ //do stuff }); 循环列表中的选项。我想知道如何获取当前循环的索引? 因为我不想让 var i = 0;循
MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL
SQLite 索引(Index) 索引(Index)是一种特殊的查找表,数据库搜索引擎用来加快数据检索。简单地说,索引是一个指向表中数据的指针。一个数据库中的索引与一本书后边的索引是非常相似的。
我是 RavenDB 的新手。我正在尝试使用多 map 索引功能,但我不确定这是否是解决我的问题的最佳方法。所以我有三个文件:Unit、Car、People。 汽车文件看起来像这样: { Id: "
我有以下数据,我想根据范围在另一个表中建立索引 我想要实现的是,例如,如果三星的销售额为 2500,则折扣为 2%,低于 3000 且高于 1000 我知道它可以通过索引来完成,与多个数组匹配,然后指
我正在检查并删除 SQL 数据库中的重复和冗余索引。 所以如果我有两个相同的索引,我会删除。 例如,如果我删除了重叠的索引... 索引1:品牌、型号 指标二:品牌、型号、价格 我删除索引 1。 相同顺
我是一名优秀的程序员,十分优秀!