Find points within a distance using CQL3 - cassandra

I have a cassandra table with user name, latitude and longitude. I would like to get a list of users who are inside the circle with a given latitude, longitude and distance.
For example: my input Lat= 78.3232 and Long = 65.3234 and distance = 30 miles.
I would like to get a list of users who are within 30 miles distance from the point 78.3232 and 65.3234. Is it possible to solve this with single CQL3 query? Or can anyone give me a hint start solving this query?

There was no geospatial support for cassandra so I found a way to Implement it mathematically to generate box coordinates around the point (That was good enough for my work) and use query to get coordinates within boundary.
I'll post the code for others reference.
public class GeoOperations {
public static final int UPPER_LATITUDE = 0;
public static final int LOWER_LATITUDE = 1;
public static final int UPPER_LONGITUDE = 2;
public static final int LOWER_LONGITUDE = 3;
private static final double KM_TO_MILES = 0.621371;
private final double Latitude;
private final double Longitude;
double Boundary[];
public GeoOperations(double init_latitude, double init_longitude) {
Latitude = init_latitude;
Longitude = init_longitude;
Boundary = new double[4];
}
public void GenerateBoxCoordinates(double Distance) {
Distance = Distance * KM_TO_MILES;
double Lat_Factor = (Distance) / 69;
Boundary[UPPER_LATITUDE] = Latitude + Lat_Factor;
Boundary[LOWER_LATITUDE] = Latitude - Lat_Factor;
double Long_Factor = (Distance) / (3960 * 2 * Math.PI / 360 * Math.cos(Latitude));
Boundary[UPPER_LONGITUDE] = Longitude + Long_Factor;
Boundary[LOWER_LONGITUDE] = Longitude - Long_Factor;
for (double x : Boundary) {
System.out.println(x);
}
}
}
And then Used Simple CQL to find coordinates within ranges
if values are like this
UPPER_LATITUDE = 60
LOWER_LATITUDE = 40
UPPER_LONGITUDE = 10
LOWER_LONGITUDE = 5
Query will be something like this (actually I used kundera with Hibernate and used a JPA query. So I havent tested it but it should work)
SELECT * FROM Points_Tablle
WHERE LATITUDE > 40
AND LATITUDE < 60
AND LONGITUDE > 5
AND LONGITUDE < 10;

If you're using DataStax enterprise, you get Geospatial out of the box. Check out Patrick's Demo:
https://github.com/PatrickCallaghan/datastax-geospatial-demo

Related

An Algorithm for producing fake audio visualizer

Does anybody knows an algorithm for making a random series of numbers (like 100 java-byte (>=-127 & <= 127) ) which when are drawn as a bar chart, would be similar to a regular audio spectrum, like those SoundCloud ones?
I'm trying to write one, it has multiple Random and Sinus calculations, but the result is very ugly, it's something between a sinus wave and an old toothbrush. I would be very thankful if you code direct me to a one which is aesthetically convincing
An algorithm with an explanation (and/or picture) is fine. A pseudocode would be very nice of you. An actual JAVA code is bonus. :D
Edit:
This is the code I'm using right now. It's convoluted but I'm basically adding a random deviation to a sinus wave with random amplitude (which I'm not sure if it was a good idea).
private static final int FREQ = 7;
private static final double DEG_TO_RAD = Math.PI / 180;
private static final int MAX_AMPLITUDE = 127;
private static final float DEVIATION = 0.1f; // 10 percent is maximum deviation
private void makeSinusoidRandomBytes() {
byte[] bytes = new byte[AUDIO_VISUALIZER_DENSITY];
for (int i = 0; i < AUDIO_VISUALIZER_DENSITY; i++) {
int amplitude = random.nextInt(MAX_AMPLITUDE) - MAX_AMPLITUDE/2;
byte dev = (byte) (random.nextInt((int) Math.max(Math.abs(2 * DEVIATION * amplitude), 1))
- Math.abs(DEVIATION * amplitude));
bytes[i] = (byte) (Math.sin(i * FREQ * DEG_TO_RAD) * amplitude - dev);
}
this.bytes = bytes;
}
A real soundwave is actually a combination of sine waves of different frequencies and amplitudes added together, not random deviations from a sine wave. The difficult part will be to choose a combination of wave amplitudes and frequencies that will produce the output that you will subjectively like! However, most sound waves have a base frequency and then a number of overtones which "fit into" that wavelength - for example it might have an overtone at 3/2 * the base frequency and at amplitude of 2/3 the base frequency. By combining these overtones and scaling the resulting waveform to the -127 - +127 range, you'll get an actual soundwave.
The following code is C#, but close enough to Java to give you an idea. It's from a game, where I needed to combine many sine waves together to create various types of oscillating effects:
/// <summary>
/// Return a value between 0 and 1 based on a sine-wave oscillating with a given combination of periods at a given point in time
/// </summary>
/// <param name="time">time to get wave value at</param>
/// <param name="periods">lengths of waves</param>
/// <returns>height of wave</returns>
public static float MultiPulse(float time, params float[] periods)
{
float c = 0;
foreach (float p in periods)
{
float cp = (MathHelper.Pi / p) * time;
float s = ((float)Math.Sin(cp) + 1) / 2;
c += s / periods.Length;
}
return c;
}
You probably want to modify that to allow you to specify different amplitudes as well as periods for the waves you are combining.
By combining many widely varying amplitudes and periods (frequencies) you should by trial and error be able to get something convincing.
Based on the idea see sharper gave me, this is the code I'm using right now:
int mainAmp = random.nextInt(MAX_AMPLITUDE) - MAX_AMPLITUDE / 2;
int overtoneAmp = random.nextInt(MAX_AMPLITUDE * 2 / 3) - MAX_AMPLITUDE / 3;
int overtone2Amp = random.nextInt(MAX_AMPLITUDE * 4 / 7) - MAX_AMPLITUDE / 2 * 7;
int mainFreq = random.nextInt(7) + 7;
int overtoneFreq = mainFreq * 3 / 2;
int overtone2Freq = mainFreq * 7 / 4;
byte[] bytes = new byte[AUDIO_VISUALIZER_DENSITY];
for (int i = 0; i < AUDIO_VISUALIZER_DENSITY; i++) {
bytes[i] = (byte) (Math.sin(i * mainFreq * DEG_TO_RAD) * mainAmp
+ Math.sin(i * overtoneFreq * DEG_TO_RAD) * overtoneAmp
+ Math.sin(i * overtone2Freq * DEG_TO_RAD) * overtone2Amp);
}
Main frequency is between 8 and 15 for my app. You can play with those. The other two overtones I'm using are (2 - 1/2)x & (2 - 1/4)x of main frequency. You can add more like (2 - 1/8)x etc. Or use another series of frequencies. I also randomize the amplitude to get a unique wave each time.
These are some waves I'm drawing using this code:

Why does this programmatically generated musical chord not sound correct?

I have the following class which generates a buffer containing sound data:
package musicbox.example;
import javax.sound.sampled.LineUnavailableException;
import musicbox.engine.SoundPlayer;
public class CChordTest {
private static final int SAMPLE_RATE = 1024 * 64;
private static final double PI2 = 2 * Math.PI;
/*
* Note frequencies in Hz.
*/
private static final double C4 = 261.626;
private static final double E4 = 329.628;
private static final double G4 = 391.995;
/**
* Returns buffer containing audio information representing the C chord
* played for the specified duration.
*
* #param duration The duration in milliseconds.
* #return Array of bytes representing the audio information.
*/
private static byte[] generateSoundBuffer(int duration) {
double durationInSeconds = duration / 1000.0;
int samples = (int) durationInSeconds * SAMPLE_RATE;
byte[] out = new byte[samples];
for (int i = 0; i < samples; i++) {
double value = 0.0;
double t = (i * durationInSeconds) / samples;
value += Math.sin(t * C4 * PI2); // C note
value += Math.sin(t * E4 * PI2); // E note
value += Math.sin(t * G4 * PI2); // G note
out[i] = (byte) (value * Byte.MAX_VALUE);
}
return out;
}
public static void main(String... args) throws LineUnavailableException {
SoundPlayer player = new SoundPlayer(SAMPLE_RATE);
player.play(generateSoundBuffer(1000));
}
}
Perhaps I'm misunderstanding some physics or math here, but it seems like each sinusoid ought to represent the sound of each note (C, E, and G), and by summing the three sinusoids, I should hear something similar to when I play those three notes simultaneously on the keyboard. What I'm hearing, however, is not even close to that.
For what it's worth, if I comment out any two of the sinusoids and keep the third, I do hear the (correct) note corresponding to that sinusoid.
Can somebody spot what I'm doing wrong?
To combine audio signals you need to average their samples, not sum them.
Divide the value by 3 before converting to byte.
You don't say in what way it sounds incorrect, adding three sin values like that you are going to get a signal that ranges from -3.0 to 3.0 and so is going to clip when you apply your *Byte.MAX_VALUE, this is why averaging probable worked for you, adding is correct its just you need to scale the result after to prevent clipping and dividing by the number of sine waves is the easiest way to do this. But if you start changing the number of sine waves dynamically and try to use the same strategy you wont get the result you expect, you have to scale the signal for when you signal is at its loudest. Remember real audio is not going to be at maximum amplitude so you don't have to worry about it two much if you synthesised audio isn't, also, the way we perceive sound volume is logarithmic so a signal at half amplitude is a difference of -3dB which is pretty close to the smallest change in amplitude we can hear.

Parse API - how do I narrow down results?

I am using the following code to get the locations for the nearest clinics in kms the code works sweet. But what I cant understand is how to get around the parse object only returning 100 objects so I guess my question should be how do i return just a subset that match the current long and lat of the clinics.
I call the below functions in my viewdIdLoadMethod
List<Clinics> _clicics;
_clicics =GetAllNearestFamousPlaces (54.269412, -0.93399086);
public List<Clinics> GetAllNearestFamousPlaces(double currentLatitude,double currentLongitude)
{
List<Clinics> Caldistance = new List<Clinics>();
var query = ParseObject.GetQuery("clinics");
query.FindAsync().ContinueWith(t =>
{
IEnumerable<ParseObject> results = t.Result;
foreach (var obj in results)
{
double distance = Distance(currentLatitude, currentLongitude, obj.Get<double>("lat"), obj.Get<double>("long"));
if (distance < 25) //nearbyplaces which are within 25 kms
{
Clinics dist = new Clinics();
dist.Name = obj.Get<string>("Name");
dist.Latitute = obj.Get<double>("lat");
dist.Longitude =obj.Get<double>("long");
Caldistance.Add(dist);
}
}
});
return Caldistance;
}
private double Distance(double lat1, double lon1, double lat2, double lon2)
{
double theta = lon1 - lon2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
dist = Math.Acos(dist);
dist = rad2deg(dist);
dist = (dist * 60 * 1.1515) / 0.6213711922; //miles to kms
return (dist);
}
private double deg2rad(double deg)
{
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad)
{
return (rad * 180.0 / Math.PI);
}
This may not be syntactically correct - I don't actually use Parse so I'm guessing based on their docs
// assume your point of origin is 54.269412, -0.93399086
// each degree of lat/long is **roughly** 100 km so we'll fudge and +- .5 to narrow down the
// list of clinics
double lat = 54.269412;
double lng = -0.93399086;
double minLong = lng - 0.5;
double maxLong = lng + 0.5;
double minLat = lat - 0.5;
double maxLat = lat + 0.5;
var query = from clinic in ParseObject.GetQuery("clinics")
where clinic.Get<double>("lat") >= minLat
and clinic.Get<double>("lat") <= maxLat
and clinic.Get<double>("long") >= minLat
and clinic.Get<double>("long") <= maxLat
select clinic;
// 1000 is the max we can request at a time
query = query.Limit(1000);
// now execute your query to get the results, and then use your Distance() function to calculate
// the precise distance and remove results that are to far away, etc

Moving from SQLite to Core Data

I'm moving my SQLite database over to Core Data. My database table looks like this:
CREATE TABLE IF NOT EXISTS stops (id integer primary key autoincrement, type text, lat real, lon real, stop_id integer unique, stop_code integer, title text, subtitle text, url text, lastupdate text
My Entity looks like this:
I'm not worries about moving the data over, it's really just a local cache that gets updated from time to time. If its empty, it will just repopulate.
My issue is I have a SQLite custom function:
static void distanceFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
{
// check that we have four arguments (lat1, lon1, lat2, lon2)
assert(argc == 4);
// check that all four arguments are non-null
if (sqlite3_value_type(argv[0]) == SQLITE_NULL || sqlite3_value_type(argv[1]) == SQLITE_NULL || sqlite3_value_type(argv[2]) == SQLITE_NULL || sqlite3_value_type(argv[3]) == SQLITE_NULL) {
sqlite3_result_null(context);
return;
}
// get the four argument values
double lat1 = sqlite3_value_double(argv[0]);
double lon1 = sqlite3_value_double(argv[1]);
double lat2 = sqlite3_value_double(argv[2]);
double lon2 = sqlite3_value_double(argv[3]);
// convert lat1 and lat2 into radians now, to avoid doing it twice below
double lat1rad = DEG2RAD(lat1);
double lat2rad = DEG2RAD(lat2);
// apply the spherical law of cosines to our latitudes and longitudes, and set the result appropriately
// 6378.1 is the approximate radius of the earth in kilometres
sqlite3_result_double(context, acos(sin(lat1rad) * sin(lat2rad) + cos(lat1rad) * cos(lat2rad) * cos(DEG2RAD(lon2) - DEG2RAD(lon1))) * 6378.1);
}
The function given a 2 latitudes and 2 longitudes would return the distance. This would let me do something like:
SELECT *, distance(lat, lon, %f, %f) as dist FROM stops WHERE dist < 1 ORDER BY dist
Now, I've got all my data in Core Data, but no idea how to do something like the SQL above with a NSFetchRequest. So how would I go about fetching entities in this manner?

how do I normalise a solr/lucene score?

I am trying to work out how to improve the scoring of solr search results. My application needs to take the score from the solr results and display a number of “stars” depending on how good the result(s) are to the query. 5 Stars = almost/exact down to 0 stars meaning not matching the search very well, e.g. only one element hits. However I am getting scores from 1.4 to 0.8660254 both are returning results that I would give 5 stars to. What I need to do is somehow turn these results in to a percentage so that I can mark these results, with the correct number of stars.
The query that I run that gives me the 1.4 score is:
euallowed:true AND(grade:"2:1")
The query that gives me the 0.8660254 score is:
euallowed:true AND(grade:"2:1" OR grade:"1st")
I've already updated the Similarity so that the tf and idf return 1.0 as I am only interested if a document has a term, not the number of that term in the document. This is what my similarity code looks like:
import org.apache.lucene.search.Similarity;
public class StudentSearchSimilarity extends Similarity {
#Override
public float lengthNorm(String fieldName, int numTerms) {
return (float) (1.0 / Math.sqrt(numTerms));
}
#Override
public float queryNorm(float sumOfSquaredWeights) {
return (float) (1.0 / Math.sqrt(sumOfSquaredWeights));
}
#Override
public float sloppyFreq(int distance) {
return 1.0f / (distance + 1);
}
#Override
public float tf(float freq) {
return (float) 1.0;
}
#Override
public float idf(int docFreq, int numDocs) {
//return (float) (Math.log(numDocs / (double) (docFreq + 1)) + 1.0);
return (float)1.0;
}
#Override
public float coord(int overlap, int maxOverlap) {
return overlap / (float) maxOverlap;
}
}
So I suppose my questions are:
How is the best way of normalising
the score so that I can work out how
many “stars” to give?
Is there another way of scoring the
results?
Thanks
Grant
To quote http://wiki.apache.org/lucene-java/ScoresAsPercentages:
People frequently want to compute a "Percentage" from Lucene scores to determine what is a "100% perfect" match vs a "50%" match. This is also somethings called a "normalized score"
Don't do this.
Seriously. Stop trying to think about your problem this way, it's not going to end well.
That page does give an example of how you could in theory do this, but it's very hard.
It's called normalized score (Scores As Percentages).
You can use the following the following parameters to achieve that:
ns = {!func}product(scale(product(query({!type=edismax v=$q}),1),0,1),100)
fq = {!frange l=20}$ns
Where 20 is your 20% threshold.
See also:
Remove results below a certain score threshold in Solr/Lucene?
http://article.gmane.org/gmane.comp.jakarta.lucene.user/12076
http://article.gmane.org/gmane.comp.jakarta.lucene.user/10810
I've never had to do anything this complicated in Solr, so there may be a way to hook this in as a plugin - but you could handle it in the client when a result set is returned. If you've sorted by relevance this should be staightforward - get the relevence of the first result (max), and the last (min). Then for each result with relevance x, you can calculate
normalisedValue = (x - min) / (max - min)
which will give you a value between 0 and 1. Multiply by 5 and round to get the number of stars.

Resources