diff options
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/query/SelectParser.java | 30 | ||||
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/yql/YqlParser.java | 18 | ||||
-rw-r--r-- | container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java | 8 | ||||
-rw-r--r-- | container-search/src/test/java/com/yahoo/select/SelectTestCase.java | 4 | ||||
-rw-r--r-- | vespajlib/src/main/java/com/yahoo/geo/DistanceParser.java (renamed from vespajlib/src/main/java/com/yahoo/geo/ParseDistance.java) | 10 | ||||
-rw-r--r-- | vespajlib/src/main/java/com/yahoo/geo/OneDegreeParser.java (renamed from vespajlib/src/main/java/com/yahoo/geo/ParseDegree.java) | 6 | ||||
-rw-r--r-- | vespajlib/src/main/java/com/yahoo/geo/ParsedDegree.java | 57 | ||||
-rw-r--r-- | vespajlib/src/test/java/com/yahoo/geo/OneDegreeParserTestCase.java (renamed from vespajlib/src/test/java/com/yahoo/geo/ParseDegreeTestCase.java) | 46 |
8 files changed, 118 insertions, 61 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java index 2476f00f194..719f16edc0a 100644 --- a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java +++ b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java @@ -3,8 +3,8 @@ package com.yahoo.search.query; import com.google.common.base.Preconditions; import com.yahoo.collections.LazyMap; -import com.yahoo.geo.ParseDegree; -import com.yahoo.geo.ParseDistance; +import com.yahoo.geo.DistanceParser; +import com.yahoo.geo.ParsedDegree; import com.yahoo.language.Language; import com.yahoo.language.process.Normalizer; import com.yahoo.prelude.IndexFacts; @@ -434,26 +434,24 @@ public class SelectParser implements Parser { var arg2 = children.get(2); var arg3 = children.get(3); var loc = new Location(); - double radius = -1; - if (arg3.type() == Type.STRING) { - radius = new ParseDistance(arg3.asString()).degrees; - } else if (arg3.type() == Type.LONG) { - radius = new ParseDistance(String.valueOf(arg3.asLong())).degrees; - } else { + if (arg3.type() != Type.STRING) { throw new IllegalArgumentException("Invalid geoLocation radius type "+arg3.type()+" for "+arg3); } + var radius = new DistanceParser(arg3.asString(), false); if (arg1.type() == Type.STRING && arg2.type() == Type.STRING) { - var coord_1 = new ParseDegree(true, children.get(1).asString()); - var coord_2 = new ParseDegree(false, children.get(2).asString()); - if (coord_1.foundLatitude && coord_2.foundLongitude) { - loc.setGeoCircle(coord_1.latitude, coord_2.longitude, radius); - } else if (coord_2.foundLatitude && coord_1.foundLongitude) { - loc.setGeoCircle(coord_2.latitude, coord_1.longitude, radius); + var c1input = children.get(1).asString(); + var c2input = children.get(2).asString(); + var coord_1 = ParsedDegree.fromString(c1input, true, false); + var coord_2 = ParsedDegree.fromString(c2input, false, true); + if (coord_1.isLatitude && coord_2.isLongitude) { + loc.setGeoCircle(coord_1.degrees, coord_2.degrees, radius.degrees); + } else if (coord_2.isLatitude && coord_1.isLongitude) { + loc.setGeoCircle(coord_2.degrees, coord_1.degrees, radius.degrees); } else { - throw new IllegalArgumentException("Invalid geoLocation coordinates '"+coord_1+"' and '"+coord_2+"'"); + throw new IllegalArgumentException("Invalid geoLocation coordinates '"+c1input+"' and '"+c2input+"'"); } } else if (arg1.type() == Type.DOUBLE && arg2.type() == Type.DOUBLE) { - loc.setGeoCircle(arg1.asDouble(), arg2.asDouble(), radius); + loc.setGeoCircle(arg1.asDouble(), arg2.asDouble(), radius.degrees); } else { throw new IllegalArgumentException("Invalid geoLocation coordinate types "+arg1.type()+" and "+arg2.type()); } diff --git a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java index 5b77da8c3b3..b2f30944ef2 100644 --- a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java +++ b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java @@ -19,8 +19,8 @@ import com.google.common.annotations.Beta; import com.google.common.base.Preconditions; import com.yahoo.collections.LazyMap; import com.yahoo.collections.LazySet; -import com.yahoo.geo.ParseDegree; -import com.yahoo.geo.ParseDistance; +import com.yahoo.geo.DistanceParser; +import com.yahoo.geo.ParsedDegree; import com.yahoo.language.Language; import com.yahoo.language.detect.Detector; import com.yahoo.language.process.Normalizer; @@ -424,14 +424,14 @@ public class YqlParser implements Parser { List<OperatorNode<ExpressionOperator>> args = ast.getArgument(1); Preconditions.checkArgument(args.size() == 4, "Expected 4 arguments, got %s.", args.size()); String field = fetchFieldRead(args.get(0)); - var coord_1 = new ParseDegree(true, fetchFieldRead(args.get(1))); - var coord_2 = new ParseDegree(false, fetchFieldRead(args.get(2))); - var radius = new ParseDistance(fetchFieldRead(args.get(3))); + var coord_1 = ParsedDegree.fromString(fetchFieldRead(args.get(1)), true, false); + var coord_2 = ParsedDegree.fromString(fetchFieldRead(args.get(2)), false, true); + var radius = new DistanceParser(fetchFieldRead(args.get(3)), false); var loc = new Location(); - if (coord_1.foundLatitude && coord_2.foundLongitude) { - loc.setGeoCircle(coord_1.latitude, coord_2.longitude, radius.degrees); - } else if (coord_2.foundLatitude && coord_1.foundLongitude) { - loc.setGeoCircle(coord_2.latitude, coord_1.longitude, radius.degrees); + if (coord_1.isLatitude && coord_2.isLongitude) { + loc.setGeoCircle(coord_1.degrees, coord_2.degrees, radius.degrees); + } else if (coord_2.isLatitude && coord_1.isLongitude) { + loc.setGeoCircle(coord_2.degrees, coord_1.degrees, radius.degrees); } else { throw new IllegalArgumentException("Invalid geoLocation coordinates '"+coord_1+"' and '"+coord_2+"'"); } diff --git a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java index 75199eeec55..62a9e27cd96 100644 --- a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java @@ -549,7 +549,7 @@ public class YqlParserTestCase { @Test public void testGeoLocation() { - assertParse("select foo from bar where geoLocation(workplace, 63.418417, 10.433033, 500000);", + assertParse("select foo from bar where geoLocation(workplace, 63.418417, 10.433033, \"0.5 deg\");", "GEO_LOCATION workplace:(2,10433033,63418417,500000,0,1,0,1921876103)"); assertParse("select foo from bar where geoLocation(headquarters, \"37.416383\", \"-122.024683\", \"100 miles\");", "GEO_LOCATION headquarters:(2,-122024683,37416383,1450561,0,1,0,3411238761)"); @@ -558,10 +558,10 @@ public class YqlParserTestCase { assertParseFail("select foo from bar where geoLocation(qux, 1, 2);", new IllegalArgumentException("Expected 4 arguments, got 3.")); - assertParseFail("select foo from bar where geoLocation(qux, 1.0, \"N1.0\", 100);", + assertParseFail("select foo from bar where geoLocation(qux, 2.0, \"N5.0\", \"0.5 deg\");", new IllegalArgumentException( - "Invalid geoLocation coordinates '1.0 -> latitude(1.0)' and 'N1.0 -> latitude(1.0)'")); - assertParse("select foo from bar where geoLocation(workplace, -12, -34, -77);", + "Invalid geoLocation coordinates 'Latitude: 2.0 degrees' and 'Latitude: 5.0 degrees'")); + assertParse("select foo from bar where geoLocation(workplace, -12, -34, \"-77 d\");", "GEO_LOCATION workplace:(2,-34000000,-12000000,-1,0,1,0,4201111954)"); } diff --git a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java index af1c1e48011..f297fd69f24 100644 --- a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java +++ b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java @@ -523,13 +523,13 @@ public class SelectTestCase { @Test public void testGeoLocation() { - assertParse("{ \"geoLocation\": [ \"workplace\", 63.418417, 10.433033, 500000 ] }", + assertParse("{ \"geoLocation\": [ \"workplace\", 63.418417, 10.433033, \"0.5 deg\" ] }", "GEO_LOCATION workplace:(2,10433033,63418417,500000,0,1,0,1921876103)"); assertParse("{ \"geoLocation\": [ \"headquarters\", \"37.416383\", \"-122.024683\", \"100 miles\" ] }", "GEO_LOCATION headquarters:(2,-122024683,37416383,1450561,0,1,0,3411238761)"); assertParse("{ \"geoLocation\": [ \"home\", \"E10.433033\", \"N63.418417\", \"5km\" ] }", "GEO_LOCATION home:(2,10433033,63418417,45066,0,1,0,1921876103)"); - assertParse("{ \"geoLocation\": [ \"workplace\", -12.0, -34.0, -77 ] }", + assertParse("{ \"geoLocation\": [ \"workplace\", -12.0, -34.0, \"-77 deg\" ] }", "GEO_LOCATION workplace:(2,-34000000,-12000000,-1,0,1,0,4201111954)"); } diff --git a/vespajlib/src/main/java/com/yahoo/geo/ParseDistance.java b/vespajlib/src/main/java/com/yahoo/geo/DistanceParser.java index 8a96ec32f8d..e184e4c36ba 100644 --- a/vespajlib/src/main/java/com/yahoo/geo/ParseDistance.java +++ b/vespajlib/src/main/java/com/yahoo/geo/DistanceParser.java @@ -2,7 +2,7 @@ package com.yahoo.geo; -public class ParseDistance { +public class DistanceParser { // according to wikipedia: // Earth's equatorial radius = 6378137 meter - not used // meters per mile = 1609.344 @@ -13,9 +13,9 @@ public class ParseDistance { public final static double km2deg = 1000.000 * 180.0 / (Math.PI * 6356752.0); public final static double mi2deg = 1609.344 * 180.0 / (Math.PI * 6356752.0); - public double degrees = 0.0; + public final double degrees; - public ParseDistance(String distance) { + public DistanceParser(String distance, boolean assume_micro_degrees) { if (distance.endsWith(" km")) { double km = Double.valueOf(distance.substring(0, distance.length()-3)); degrees = km * km2deg; @@ -48,8 +48,10 @@ public class ParseDistance { degrees = Double.valueOf(distance.substring(0, distance.length()-3)); } else if (distance.endsWith("d")) { degrees = Double.valueOf(distance.substring(0, distance.length()-1)); - } else { + } else if (assume_micro_degrees) { degrees = Integer.parseInt(distance) * 0.000001; + } else { + throw new IllegalArgumentException("missing unit for distance: "+distance); } } diff --git a/vespajlib/src/main/java/com/yahoo/geo/ParseDegree.java b/vespajlib/src/main/java/com/yahoo/geo/OneDegreeParser.java index a6200ed60c6..2af85ad0b9e 100644 --- a/vespajlib/src/main/java/com/yahoo/geo/ParseDegree.java +++ b/vespajlib/src/main/java/com/yahoo/geo/OneDegreeParser.java @@ -3,11 +3,11 @@ package com.yahoo.geo; /** - * utility for parsing geographical coordinates + * utility for parsing one geographical coordinate * * @author arnej27959 **/ -public class ParseDegree { +class OneDegreeParser { /** * the parsed latitude (degrees north if positive) **/ @@ -82,7 +82,7 @@ public class ParseDegree { * @param lat_or_lon Latitude or longitude * **/ - public ParseDegree(boolean assume_n_s, String lat_or_lon) throws IllegalArgumentException { + public OneDegreeParser(boolean assume_n_s, String lat_or_lon) throws IllegalArgumentException { this.parseString = lat_or_lon; this.len = parseString.length(); consumeString(assume_n_s); diff --git a/vespajlib/src/main/java/com/yahoo/geo/ParsedDegree.java b/vespajlib/src/main/java/com/yahoo/geo/ParsedDegree.java new file mode 100644 index 00000000000..0abcbd0c606 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/geo/ParsedDegree.java @@ -0,0 +1,57 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +package com.yahoo.geo; + +/** + * utility for holding one geographical coordinate + * + * @author arnej27959 + **/ +public class ParsedDegree { + /** + * the parsed latitude or longitude + * Degrees north or east if positive + * Degrees south or west if negative + **/ + public final double degrees; + + // one of these two flag will be true: + public final boolean isLatitude; + public final boolean isLongitude; + + public ParsedDegree(double value, boolean isLat, boolean isLon) { + this.degrees = value; + this.isLatitude = isLat; + this.isLongitude = isLon; + if (isLat && isLon) { + throw new IllegalArgumentException("value cannot be both latitude and longitude at once"); + } + if (isLat || isLon) { + return; + } + throw new IllegalArgumentException("value must be either latitude or longitude"); + } + + static public ParsedDegree fromString(String toParse, boolean assumeLatitude, boolean assumeLongitude) { + if (assumeLatitude && assumeLongitude) { + throw new IllegalArgumentException("value cannot be both latitude and longitude at once"); + } + var parser = new OneDegreeParser(assumeLatitude, toParse); + if (parser.foundLatitude) { + return new ParsedDegree(parser.latitude, true, false); + } + if (parser.foundLongitude) { + return new ParsedDegree(parser.longitude, false, true); + } + throw new IllegalArgumentException("could not parse: "+toParse); + } + + public String toString() { + if (isLatitude) { + return "Latitude: "+degrees+" degrees"; + } else { + return "Longitude: "+degrees+" degrees"; + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/geo/ParseDegreeTestCase.java b/vespajlib/src/test/java/com/yahoo/geo/OneDegreeParserTestCase.java index 3ca2d7ce4f8..6a7ea5e826d 100644 --- a/vespajlib/src/test/java/com/yahoo/geo/ParseDegreeTestCase.java +++ b/vespajlib/src/test/java/com/yahoo/geo/OneDegreeParserTestCase.java @@ -8,24 +8,24 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** - * Tests for the ParseDegree class. + * Tests for the OneDegreeParser class. * * @author arnej27959 */ -public class ParseDegreeTestCase { +public class OneDegreeParserTestCase { private static final double delta = 0.000000000001; - private ParseDegree parser; + private OneDegreeParser parser; private void checkLat(boolean ans, String to_parse, double expected) { - parser = new ParseDegree(ans, to_parse); + parser = new OneDegreeParser(ans, to_parse); assertEquals(expected, parser.latitude, delta); assertTrue(parser.foundLatitude); assertFalse(parser.foundLongitude); } private void checkLon(boolean ans, String to_parse, double expected) { - parser = new ParseDegree(ans, to_parse); + parser = new OneDegreeParser(ans, to_parse); assertEquals(expected, parser.longitude, delta); assertFalse(parser.foundLatitude); assertTrue(parser.foundLongitude); @@ -146,49 +146,49 @@ public class ParseDegreeTestCase { public void testAboveBoundary() { String message = ""; try { - parser = new ParseDegree(false, "N90.0001"); + parser = new OneDegreeParser(false, "N90.0001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("out of range [-90,+90]: 90.0001", message); try { - parser = new ParseDegree(false, "S90.0001"); + parser = new OneDegreeParser(false, "S90.0001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("out of range [-90,+90]: -90.0001", message); try { - parser = new ParseDegree(true, "E180.0001"); + parser = new OneDegreeParser(true, "E180.0001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("out of range [-180,+180]: 180.0001", message); try { - parser = new ParseDegree(true, "W180.0001"); + parser = new OneDegreeParser(true, "W180.0001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("out of range [-180,+180]: -180.0001", message); try { - parser = new ParseDegree(false, "N90.000001"); + parser = new OneDegreeParser(false, "N90.000001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("out of range [-90,+90]: 90.000001", message); try { - parser = new ParseDegree(false, "S90.000001"); + parser = new OneDegreeParser(false, "S90.000001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("out of range [-90,+90]: -90.000001", message); try { - parser = new ParseDegree(true, "E180.000001"); + parser = new OneDegreeParser(true, "E180.000001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("out of range [-180,+180]: 180.000001", message); try { - parser = new ParseDegree(true, "W180.000001"); + parser = new OneDegreeParser(true, "W180.000001"); } catch (IllegalArgumentException e) { message = e.getMessage(); } @@ -202,61 +202,61 @@ public class ParseDegreeTestCase { public void testInputErrors() { String message = ""; try { - parser = new ParseDegree(false, "N90S90"); + parser = new OneDegreeParser(false, "N90S90"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("already set direction once, cannot add direction: S", message); try { - parser = new ParseDegree(false, "E120W120"); + parser = new OneDegreeParser(false, "E120W120"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("already set direction once, cannot add direction: W", message); try { - parser = new ParseDegree(false, "E"); + parser = new OneDegreeParser(false, "E"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("end of field without any number seen", message); try { - parser = new ParseDegree(false, ""); + parser = new OneDegreeParser(false, ""); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("end of field without any number seen", message); try { - parser = new ParseDegree(false, "NW25"); + parser = new OneDegreeParser(false, "NW25"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("already set direction once, cannot add direction: W", message); try { - parser = new ParseDegree(false, "N16.25\u00B0"); + parser = new OneDegreeParser(false, "N16.25\u00B0"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("cannot have fractional degrees before degrees sign", message); try { - parser = new ParseDegree(false, "N16\u00B022.40'"); + parser = new OneDegreeParser(false, "N16\u00B022.40'"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("cannot have fractional minutes before minutes sign", message); try { - parser = new ParseDegree(false, ""); + parser = new OneDegreeParser(false, ""); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("end of field without any number seen", message); try { - parser = new ParseDegree(false, "Yahoo!"); + parser = new OneDegreeParser(false, "Yahoo!"); } catch (IllegalArgumentException e) { message = e.getMessage(); } assertEquals("invalid character: Y", message); try { - parser = new ParseDegree(false, "N63O025.105"); + parser = new OneDegreeParser(false, "N63O025.105"); } catch (IllegalArgumentException e) { message = e.getMessage(); } |