Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Geospatial search with timestamp using Lucene

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?

like image 965
user2869520 Avatar asked Oct 21 '25 21:10

user2869520


1 Answers

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);
        }
    }
like image 126
Aakanksha Avatar answered Oct 23 '25 13:10

Aakanksha