test.demo.KnnQuery.java Source code

Java tutorial

Introduction

Here is the source code for test.demo.KnnQuery.java

Source

/**
 *
 * Copyright (c) 2002-2008 The P-Grid Team, All Rights Reserved.
 *
 * This file is part of the P-Grid package.
 * P-Grid homepage: http://www.p-grid.org/
 *  
 * The P-Grid package is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * The P-Grid package is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with the P-Grid package.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package test.demo;

import p2p.basic.*;
import p2p.basic.events.P2PListener;
import p2p.index.events.SearchListener;
import p2p.index.*;
import pgrid.interfaces.basic.PGridP2P;
import pgrid.interfaces.basic.PGridP2PFactory;
import pgrid.interfaces.index.PGridIndexFactory;
import pgrid.interfaces.index.DefaultTypeHandler;
import pgrid.PGridHost;
import pgrid.core.search.SearchManager;

import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.logging.Level;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import mgrid.core.MGridUtils;
import mgrid.core.Point;
import mgrid.core.PQSort;

import com.google.common.base.Functions;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
import com.google.uzaygezen.core.BacktrackingQueryBuilder;
import com.google.uzaygezen.core.BigIntegerContent;
import com.google.uzaygezen.core.BitVector;
import com.google.uzaygezen.core.BitVectorFactories;
import com.google.uzaygezen.core.CompactHilbertCurve;
import com.google.uzaygezen.core.FilteredIndexRange;
import com.google.uzaygezen.core.LongContent;
import com.google.uzaygezen.core.MultiDimensionalSpec;
import com.google.uzaygezen.core.NodeValue;
import com.google.uzaygezen.core.PlainFilterCombiner;
import com.google.uzaygezen.core.Pow2LengthBitSetRange;
import com.google.uzaygezen.core.Query;
import com.google.uzaygezen.core.QueryBuilder;
import com.google.uzaygezen.core.RegionInspector;
import com.google.uzaygezen.core.SimpleRegionInspector;
import com.google.uzaygezen.core.SpaceFillingCurve;
import com.google.uzaygezen.core.ZoomingSpaceVisitorAdapter;
import com.google.uzaygezen.core.ranges.LongRange;
import com.google.uzaygezen.core.ranges.LongRangeHome;

import test.WaitingArea;

/**
 * Sample peer listens for messages and displays them on the command line.
 * 
 * @author A. Nevski and Renault JOHN
 */
public class KnnQuery implements SearchListener, P2PListener {

    private static P2PFactory p2pFactory;
    private static P2P p2p;

    private static IndexFactory indexFactory;
    private static Index index;

    private static Type type;

    private static long startTime = 0L;
    private static long endTime = 0L;

    private static PriorityBlockingQueue<Point> nnQueue;

    // private static List<Point> actual ;

    public static Object lock = new Object();

    private static boolean allResults;

    private static Long queryx, queryy;

    private static int k;

    public static volatile int requestCount = 0;

    public static volatile int responseCount = 0;

    public static double delta;

    /**
     * The P2P facility.
     */
    protected PGridP2P mPGridP2P = PGridP2P.sharedInstance();

    /**
     * Create an instance of sample receiving peer.
     * 
     */
    public KnnQuery() {
        allResults = false;
    }

    /**
     * Let the sample peer send a message.
     * 
     * @param args
     *            the command line arguments to be passed on to the peer-to-peer
     *            layer
     * @see test.CommandLineArgs usage
     */
    public static void main(String[] args) throws IOException {
        test.CommandLineArgs cla = new test.CommandLineArgs(args);
        KnnQuery storage = new KnnQuery();

        Properties properties = cla.getOtherProperties();
        InetAddress bootIP = cla.getAddress();
        int bootPort = cla.getPort();
        // Set the debug mode to the minimum. Debug can be set to a number
        // between 0-3
        properties.setProperty(PGridP2P.PROP_DEBUG_LEVEL, "3");
        // Use a verbose mode
        properties.setProperty(PGridP2P.PROP_VERBOSE_MODE, "false");

        // Get an instance of the P2PFactory
        p2pFactory = PGridP2PFactory.sharedInstance();
        System.out.println("Acquired P-Grid factory reference. ");

        // Get an instance of the P2P object, aka P-Grid
        p2p = p2pFactory.createP2P(properties);
        System.out.println("Created a P2P instance. ");

        // Create an instance of the bootstrap host that will be use to
        // bootstrap the
        // network
        Peer bootstrap = null;
        try {
            bootstrap = p2pFactory.createPeer(bootIP, bootPort);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        System.out.println("Bootstrap Peer instance Created.");

        // Get an instance of the StorageFactory
        indexFactory = PGridIndexFactory.sharedInstance();
        System.out.println("Storage factory reference acquired. ");

        // Get an instance of the Storage object, aka MGridStorage
        index = indexFactory.createIndex(p2p);
        System.out.println("Storage instance acquired. ");

        // creating and registering data type.
        type = indexFactory.createType("SimpleType");
        TypeHandler handler = new DefaultTypeHandler(type);
        indexFactory.registerTypeHandler(type, handler);

        // Try to join the network
        p2p.join(bootstrap);
        System.out.println(
                "Network joined. Current key range (path) is: " + ((PGridHost) p2p.getLocalPeer()).getPath());

        // add this object as a p2p listener
        p2p.addP2PListener(storage.returnThis());

        // wait for the network to be created.
        System.out.println("Waiting while structuring the network.");

        WaitingArea.waitTillSignal(1000 * 2);

        // calculate k-nearest neighbours

        queryx = 66400L;
        queryy = 2000L;

        k = 1000000;
        double totalPoints = 400000000;
        double D = MGridUtils.nextRange(k, totalPoints);
        delta = Math.ceil((D / k));
        System.out.println("Creating nearest neighbour query with k=" + k + " and point (" + queryx + "," + queryy
                + ")" + " delta " + delta);

        boolean sizeCheck = false;

        while (sizeCheck == false) {
            PQSort sort = new PQSort(queryx, queryy);
            nnQueue = new PriorityBlockingQueue<Point>(k, sort);
            startTime = System.currentTimeMillis();
            storage.hilbertknnQuery(storage.returnThis(), queryx, queryy, delta);

            Runnable runA = new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        //      System.out.println("starting "+Thread.currentThread().getName());   
                        while (responseCount < requestCount) {
                            allResults = false;
                        }
                        allResults = true;
                        //      System.out.println("Notifying main thread");
                        lock.notifyAll();

                    } //  end of sync block
                }
            };

            Thread threadA = new Thread(runA, "HelperThread");
            threadA.start();

            synchronized (lock) {
                while (allResults == false) {
                    try {
                        //   System.out.println(Thread.currentThread().getName()+" is waiting for the resultSet and going into sleep");      
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } // end of while 
            } // end of sync
            if (nnQueue.size() < k) {
                System.out.println("queue size " + nnQueue.size() + " is less than k " + k);
                //   System.out.println("resetting all ");
                requestCount = 0;
                responseCount = 0;
                delta += delta;
                allResults = false;
                nnQueue.clear();
                //   System.out.println("queue size "+nnQueue.size()+" request "+requestCount+" response "+responseCount+" delta "+delta);;
            } else {
                sizeCheck = true;
            }
        }
        //   System.out.println(Thread.currentThread().getName()+" is not waiting this time");

        // show top k results 
        storage.showKnnResults();

        System.out.println("Demo over, will shutdown in 30s.");
        test.WaitingArea.waitTillSignal(1000 * 30);

        // shutting down the p2p. This is not a mandatory phase,
        // but it can avoid some manager to throw exceptions
        System.out.println("shutdown ...");
        p2p.leave();
        index.shutdown();

    }

    KnnQuery returnThis() {
        return this;
    }

    /**
     * Implementation of the P2PListener interface. Is invoked when a new
     * message is received and this node is responsible for the message's
     * destination key. Reassembles the message text and displays it on the
     * command line.
     */
    public void newMessage(Message message, Peer origin) {
        String str = "";
        try {
            str = new String(message.getData(), "ISO-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println("Received message: " + str + " from " + origin.toString());
    }

    /**
     * Invoked when a new search result is available
     * 
     * @param guid
     *            the GUID of the original query
     * @param results
     *            a Collection of DataItems matching the original query
     */
    @SuppressWarnings("rawtypes")
    public void newSearchResult(GUID guid, Collection results) {

        for (Iterator it = results.iterator(); it.hasNext();) {
            IndexEntry entry = (IndexEntry) it.next();
            BitVector[] xy = MGridUtils.HilbertInverseConvertor(Long.parseLong(entry.getKey().toString(), 2));
            Long x = xy[0].toExactLong();
            Long y = xy[1].toExactLong();
            if (!((queryx == x) & (queryy == y))) {
                Point point = new Point(x, y, entry.getmPointID());
                //   System.out.println("adding point :"+x+" "+y);
                nnQueue.add(point);
            }
        }

    }// end of new Search

    public void newSearchResult(GUID guid, int resultSize) {
        //      System.out.println(" resultsize: "+resultSize);
        for (int i = 0; i < resultSize; i++) {
            Point point = new Point(0L, 0L, 0L);
            nnQueue.add(point);
        }
    }

    /**
     * Invoked when a search resulted in no results.
     * 
     * @param guid
     *            the GUID of the original query
     */
    public void noResultsFound(GUID guid) {
        // System.out.println("No results found for search.");
    }

    /**
     * Invoked when a search failed.
     * 
     * @param guid
     *            the GUID of the original query
     */
    public void searchFailed(GUID guid) {
        //   System.out.println("Search failed.");
    }

    /**
     * Invoked when a search finished.
     * 
     * @param guid
     *            the GUID of the original query
     */
    public void searchFinished(GUID guid) {

        responseCount++;
        //   System.out.println("request : "+requestCount +" response "+responseCount);
        //   System.out.println("Search finished.");
    }

    /**
     * Invoked when a search started (reached a responsible peer).
     * 
     * @param guid
     *            the GUID of the original query
     * @param message
     *            the explanation message.
     */
    public void searchStarted(GUID guid, String message) {
        System.out.println("Search started.");
    }

    private static List<LongRange> rangesToQueryRegion(int[][] ranges) {
        List<LongRange> region = new ArrayList<>();
        for (int j = 0; j < ranges.length; ++j) {
            region.add(LongRange.of(ranges[j][0], ranges[j][1] + 1));
        }
        return region;
    }

    private static List<FilteredIndexRange<Object, LongRange>> queryto(List<LongRange> region,
            SpaceFillingCurve sfc, int maxRanges,
            Map<Pow2LengthBitSetRange, NodeValue<BigIntegerContent>> rolledupMap) {
        List<? extends List<LongRange>> x = ImmutableList.of(region);
        LongContent zero = new LongContent(0L);
        LongContent one = new LongContent(1L);
        Object filter = "";

        RegionInspector<Object, LongContent> simpleRegionInspector = SimpleRegionInspector.create(x, one,
                Functions.constant(filter), LongRangeHome.INSTANCE, zero);

        // Not using using sub-ranges here.
        PlainFilterCombiner<Object, Long, LongContent, LongRange> combiner = new PlainFilterCombiner<>(filter);
        QueryBuilder<Object, LongRange> queryBuilder = BacktrackingQueryBuilder.create(simpleRegionInspector,
                combiner, maxRanges, true, LongRangeHome.INSTANCE, zero);
        sfc.accept(new ZoomingSpaceVisitorAdapter(sfc, queryBuilder));
        Query<Object, LongRange> query = queryBuilder.get();
        return query.getFilteredIndexRanges();
    }

    private void hilbertknnQuery(SearchListener listner, Long queryx, Long queryy, double delta) {
        MultiDimensionalSpec spec = new MultiDimensionalSpec(Ints.asList(MGridUtils.xBits, MGridUtils.yBits));
        SpaceFillingCurve sfc = new CompactHilbertCurve(spec);
        int[] maxLengthPerDimension = new int[spec.getBitsPerDimension().size()];
        int m = 17;
        Arrays.fill(maxLengthPerDimension, m);

        int[][] window = MGridUtils.calculateRanges(queryx, queryy, delta);
        int[][] ranges = generateRanges(spec, maxLengthPerDimension, window);
        final int maxFilteredRanges = 20;

        List<LongRange> region = rangesToQueryRegion(ranges);
        List<FilteredIndexRange<Object, LongRange>> indexRanges = queryto(region, sfc, maxFilteredRanges, null);
        BitVector start = BitVectorFactories.OPTIMAL.apply(spec.sumBitsPerDimension());
        BitVector end = BitVectorFactories.OPTIMAL.apply(spec.sumBitsPerDimension());
        for (int i = 0; i < indexRanges.size(); ++i) {
            FilteredIndexRange<Object, LongRange> indexRange = indexRanges.get(i);
            Long startLong = indexRange.getIndexRange().getStart();
            start.copyFrom(startLong);
            Long endLong = indexRange.getIndexRange().getEnd();
            end.copyFrom(endLong);
            Long xmin = new Long(window[0][0]);
            Long xmax = new Long(window[1][0]);
            Long ymin = new Long(window[0][1]);
            Long ymax = new Long(window[1][1]);
            System.out.println("Searching in between " + start.toString() + " " + end.toString());
            p2p.index.Query rangeQuery = indexFactory.createQuery(type, start.toString(), end.toString(), xmin,
                    xmax, ymin, ymax);
            String localpath = mPGridP2P.getLocalPath();
            String tempLowerkey = start.toString().substring(0, localpath.length());
            Long lkey = Long.parseLong(tempLowerkey, 2);
            String tempHigherKey = end.toString().substring(0, localpath.length());
            Long hkey = Long.parseLong(tempHigherKey, 2);
            Long numPeers = (hkey - lkey) + 1;
            requestCount += numPeers;
            System.out.println(" request count is : " + requestCount);
            index.search(rangeQuery, listner);

        }
    }

    private static int[][] generateRanges(MultiDimensionalSpec spec, int[] maxLengthPerDimension, int[][] window) {
        int[][] ranges = new int[spec.getBitsPerDimension().size()][2];
        // both ends inclusive xmin , xmax , ymin , ymax
        ranges[0][0] = window[0][0];
        ranges[0][1] = window[1][0];
        ranges[1][0] = window[0][1];
        ranges[1][1] = window[1][1];
        return ranges;
    }

    private void showKnnResults() {
        if (!nnQueue.isEmpty()) {
            endTime = System.currentTimeMillis();
            System.out.println(nnQueue.size() + " hits in time " + ((endTime - startTime)) + " ms.");
            /*for (int i = 0; i < k; i++) {
               endTime = System.nanoTime();
               Point p = ((PriorityBlockingQueue<Point>) nnQueue).poll();
            //   System.out.println(p.x + " " + p.y + " " + p.id + " "
            //         + ((endTime - startTime) / 1000000) + " ms.");
               System.out.println(nnQueue.size()+" hits in time "+ ((endTime - startTime) / 1000000) + " ms.");
            }*/

        }
    }

}