I have an assignment to find cab drivers close to a given user's location(similar to Grab/Lyft). I have the drivers' location(latitude, longitude) with timestamp. This data is pushed by their mobile to my server every 2 minutes. When a user requests a ride, I need to find the nearest driver available using the drivers' data. I'm trying to use Lucene's GeoSpatial search for this. I've used the drivers data to be indexed and search based on the latitude and longitude of the user. I'm also able to search with a given latitude/longitude combination and get the nearest driver(s) with a distance parameter. But I don't know how I can add another parameter to the search query to specify the timestamp of the driver's data as well. For e.g., I want to search for only drivers who are near a given location at a particular timestamp. Can someone help me with this? Here's the code snippet I'm using:
package com.test.trials;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.spatial3d.Geo3DPoint;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.document.LatLonPoint;
public class LuceneTrial {
private IndexSearcher searcher;
public static void main(String[] args) throws IOException {
LuceneTrial trial = new LuceneTrial();
trial.generateData();
trial.search();
}
private void generateData() throws IOException {
Directory dir = FSDirectory.open(Paths.get("C:/temp/Lucene"));
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
IndexWriter writer = new IndexWriter(dir, iwc);
try (BufferedReader br = new BufferedReader(new FileReader(
"C:/temp/Lucene/Drivers.csv"))) {
String line;
String[] fieldNames = new String[] { "Driver ID", "Latitude", "Longitude", "Time" };
while ((line = br.readLine()) != null) {
// process the line.
String[] tags = line.split(",");
Document doc = new Document();
for (int i = 0; i < fieldNames.length; i++)
doc.add(new StoredField(fieldNames[i], tags[i]));
// Add a latlon point to index
try {
doc.add(new LatLonPoint("latlon", Double
.parseDouble(tags[1]), Double.parseDouble(tags[2])));
Geo3DPoint point = new Geo3DPoint("geo3d",
Double.parseDouble(tags[1]),
Double.parseDouble(tags[2]));
doc.add(point);
} catch (Exception e) {
System.out.println("Skipped: " + line);
}
writer.addDocument(doc);
}
}
searcher = new IndexSearcher(DirectoryReader.open(writer));
}
public void search() throws IOException {
System.out
.println("\nLatLonQuery around given point, 10km radius --------------------------------------");
TopDocs docs = searcher.search(LatLonPoint.newDistanceQuery("latlon",
6.9270790, 79.8612430, 10 * 1000), 20);
for (ScoreDoc scoreDoc : docs.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
System.out.println(doc);
}
}
}
And Here's the sample data I'm using:
Driver ID Latitude Longitude Time
1 -6.081689 145.391881 7:01:17
2 -5.207083 145.7887 8:32:40
3 -5.826789 144.295861 8:40:49
4 -6.569828 146.726242 8:57:33
5 -9.443383 147.22005 6:14:26
6 -3.583828 143.669186 8:13:35
7 61.160517 -45.425978 8:58:24
8 64.190922 -51.678064 7:42:16
9 67.016969 -50.689325 6:52:20
10 76.531203 -68.703161 6:08:21
11 65.659994 -18.072703 7:57:45
12 65.283333 -14.401389 7:32:23
13 64.295556 -15.227222 8:20:26
14 65.952328 -17.425978 8:51:34
15 66.058056 -23.135278 8:33:43
16 63.985 -22.605556 7:39:35
17 65.555833 -23.965 7:20:54
18 64.13 -21.940556 7:37:48
19 66.133333 -18.916667 6:46:36
20 63.424303 -20.278875 7:15:12
21 46.485001 -84.509445 6:14:15
22 50.056389 -97.0325 7:12:15
23 44.639721 -63.499444 6:15:31
24 51.391944 -56.083056 7:15:50
25 49.082222 -125.7725 6:52:22
Can someone show me how I can search for the drivers based on two attributes - distance and time?
You can use BooleanQuery to solve your use case. Here's how your search function might look like:
public void search() throws IOException {
System.out
.println("\nLatLonQuery around given point, 10km radius --------------------------------------");
Query distQuery = LatLonPoint.newDistanceQuery("latlon", -6.08165, 145.8612430, dist * 1000);
long startTime=0;//adjust according to your needs
long endTime=Long.Max_VALUE;//adjust according to your needs
Query timeQuery = LongPoint.newRangeQuery("timestamp", startTime, endTime);
BooleanQuery booleanQuery = new BooleanQuery.Builder()
.add(distQuery, Occur.MUST)
.add(timeQuery, Occur.MUST)
.build();
TopDocs docs = searcher.search(booleanQuery, 20);
for (ScoreDoc scoreDoc : docs.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
System.out.println(doc);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With