You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by is...@apache.org on 2017/03/19 15:57:46 UTC
[12/12] lucene-solr:jira/solr-6736: Merge master into jira/solr-6736
branch
Merge master into jira/solr-6736 branch
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/887d1b18
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/887d1b18
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/887d1b18
Branch: refs/heads/jira/solr-6736
Commit: 887d1b18b9bc148d031dc5242888da74b61c5b1a
Parents: f95bc11
Author: Ishan Chattopadhyaya <is...@apache.org>
Authored: Sun Mar 19 21:27:14 2017 +0530
Committer: Ishan Chattopadhyaya <is...@apache.org>
Committed: Sun Mar 19 21:27:14 2017 +0530
----------------------------------------------------------------------
dev-tools/scripts/buildAndPushRelease.py | 64 ++
dev-tools/scripts/smokeTestRelease.py | 2 +-
lucene/CHANGES.txt | 20 +
.../byTask/feeds/EnwikiContentSource.java | 2 +-
.../benchmark/byTask/tasks/ForceMergeTask.java | 2 +-
.../org/apache/lucene/document/DoubleRange.java | 271 +++++
.../org/apache/lucene/document/FloatRange.java | 271 +++++
.../org/apache/lucene/document/IntRange.java | 271 +++++
.../org/apache/lucene/document/LongRange.java | 269 +++++
.../apache/lucene/document/RangeFieldQuery.java | 340 ++++++
.../org/apache/lucene/index/PointValues.java | 2 +-
.../org/apache/lucene/util/QueryBuilder.java | 46 +-
.../java/org/apache/lucene/util/Version.java | 7 +
.../search/TestDoubleRangeFieldQueries.java | 251 +++++
.../search/TestFloatRangeFieldQueries.java | 251 +++++
.../lucene/search/TestIntRangeFieldQueries.java | 251 +++++
.../search/TestLongRangeFieldQueries.java | 251 +++++
.../org/apache/lucene/util/fst/TestFSTs.java | 4 +-
.../lucene/search/join/TestBlockJoin.java | 2 +-
.../lucene/document/InetAddressPoint.java | 313 ++++++
.../lucene/document/InetAddressRange.java | 168 +++
.../lucene/document/TestInetAddressPoint.java | 176 +++
.../search/TestDiversifiedTopDocsCollector.java | 2 +-
.../search/TestInetAddressRangeQueries.java | 215 ++++
.../queries/function/TestValueSources.java | 6 +-
.../queryparser/classic/QueryParserBase.java | 6 +-
.../standard/parser/StandardSyntaxParser.java | 8 +-
.../standard/parser/StandardSyntaxParser.jj | 8 +-
.../surround/parser/QueryParser.java | 2 +-
.../queryparser/surround/parser/QueryParser.jj | 2 +-
.../xml/builders/PointRangeQueryBuilder.java | 16 +-
.../queryparser/classic/TestQueryParser.java | 2 +-
.../xml/CoreParserTestIndexData.java | 2 +-
.../lucene/document/DoubleRangeField.java | 282 -----
.../apache/lucene/document/FloatRangeField.java | 282 -----
.../lucene/document/InetAddressPoint.java | 313 ------
.../apache/lucene/document/IntRangeField.java | 282 -----
.../lucene/document/LatLonDocValuesField.java | 2 +-
.../apache/lucene/document/LongRangeField.java | 280 -----
.../apache/lucene/document/RangeFieldQuery.java | 340 ------
.../org/apache/lucene/document/package.html | 3 +-
.../lucene/document/TestDoubleRangeField.java | 10 +-
.../lucene/document/TestInetAddressPoint.java | 176 ---
.../search/BaseRangeFieldQueryTestCase.java | 344 ------
.../search/TestDoubleRangeFieldQueries.java | 251 -----
.../search/TestFloatRangeFieldQueries.java | 251 -----
.../lucene/search/TestIntRangeFieldQueries.java | 251 -----
.../search/TestLongRangeFieldQueries.java | 251 -----
.../lucene/spatial3d/Geo3DDocValuesField.java | 2 +-
.../search/BaseRangeFieldQueryTestCase.java | 346 ++++++
solr/CHANGES.txt | 92 ++
solr/bin/solr | 57 +-
solr/bin/solr.in.sh | 11 +-
.../apache/solr/schema/ICUCollationField.java | 5 +-
.../analytics/util/RangeEndpointCalculator.java | 8 +-
.../handler/dataimport/MailEntityProcessor.java | 2 +-
.../TikaLanguageIdentifierUpdateProcessor.java | 5 +-
.../apache/solr/ltr/feature/SolrFeature.java | 3 +
.../featureExamples/external_features.json | 6 +
.../solr/ltr/TestSelectiveWeightCreation.java | 8 +-
.../solr/ltr/feature/TestExternalFeatures.java | 25 +-
.../solr/hadoop/TreeMergeOutputFormat.java | 3 +-
.../java/org/apache/solr/response/PageTool.java | 2 +-
.../org/apache/solr/cloud/ElectionContext.java | 20 +-
.../OverseerAutoReplicaFailoverThread.java | 6 +-
.../cloud/OverseerCollectionMessageHandler.java | 1 +
.../org/apache/solr/cloud/RecoveryStrategy.java | 135 ++-
.../apache/solr/cloud/ReplicateFromLeader.java | 124 +++
.../org/apache/solr/cloud/ZkController.java | 39 +-
.../org/apache/solr/core/CoreContainer.java | 30 +-
.../org/apache/solr/core/RequestParams.java | 2 +-
.../java/org/apache/solr/core/SolrConfig.java | 2 +
.../src/java/org/apache/solr/core/SolrCore.java | 65 +-
.../org/apache/solr/handler/IndexFetcher.java | 40 +-
.../apache/solr/handler/ReplicationHandler.java | 30 +-
.../org/apache/solr/handler/SQLHandler.java | 37 +-
.../solr/handler/admin/CollectionsHandler.java | 4 +-
.../solr/handler/admin/MetricsHandler.java | 6 +-
.../handler/admin/PropertiesRequestHandler.java | 27 +-
.../solr/handler/admin/SystemInfoHandler.java | 20 +-
.../handler/component/RangeFacetRequest.java | 8 +-
.../handler/component/RealTimeGetComponent.java | 36 +-
.../solr/handler/component/SearchHandler.java | 5 +
.../apache/solr/handler/sql/SolrEnumerator.java | 4 +-
.../org/apache/solr/handler/sql/SolrTable.java | 10 +-
.../UninvertDocValuesMergePolicyFactory.java | 218 ++++
.../apache/solr/metrics/SolrMetricManager.java | 5 +-
.../reporters/solr/SolrClusterReporter.java | 10 +-
.../metrics/reporters/solr/SolrReporter.java | 2 +-
.../reporters/solr/SolrShardReporter.java | 5 +-
.../org/apache/solr/parser/QueryParser.java | 417 +++++--
.../java/org/apache/solr/parser/QueryParser.jj | 276 +++--
.../apache/solr/parser/SolrQueryParserBase.java | 217 +++-
.../transform/BaseEditorialTransformer.java | 36 +-
.../solr/rest/schema/FieldTypeXmlAdapter.java | 25 +-
.../solr/schema/AbstractSpatialFieldType.java | 2 +-
.../solr/schema/AbstractSubTypeFieldType.java | 17 +-
.../org/apache/solr/schema/BinaryField.java | 9 +
.../java/org/apache/solr/schema/BoolField.java | 3 -
.../org/apache/solr/schema/CollationField.java | 5 +-
.../org/apache/solr/schema/DatePointField.java | 11 -
.../apache/solr/schema/DoublePointField.java | 12 -
.../java/org/apache/solr/schema/EnumField.java | 16 -
.../org/apache/solr/schema/FieldProperties.java | 43 +-
.../java/org/apache/solr/schema/FieldType.java | 31 +-
.../org/apache/solr/schema/FloatPointField.java | 13 -
.../org/apache/solr/schema/IntPointField.java | 11 -
.../solr/schema/LatLonPointSpatialField.java | 271 +++++
.../java/org/apache/solr/schema/LatLonType.java | 12 +-
.../org/apache/solr/schema/LongPointField.java | 11 -
.../apache/solr/schema/NumericFieldType.java | 4 +-
.../java/org/apache/solr/schema/PointField.java | 4 -
.../java/org/apache/solr/schema/PointType.java | 14 +-
.../apache/solr/schema/PrimitiveFieldType.java | 4 +
.../org/apache/solr/schema/SchemaField.java | 7 +-
.../schema/SpatialPointVectorFieldType.java | 7 -
.../java/org/apache/solr/schema/StrField.java | 4 -
.../java/org/apache/solr/schema/TrieField.java | 20 -
.../solr/search/ExtendedDismaxQParser.java | 175 ++-
.../java/org/apache/solr/search/Grouping.java | 2 +-
.../org/apache/solr/search/LuceneQParser.java | 3 +
.../apache/solr/search/LuceneQParserPlugin.java | 2 +
.../QueryParserConfigurationException.java | 24 +
.../org/apache/solr/search/QueryParsing.java | 1 +
.../apache/solr/search/SolrIndexSearcher.java | 270 +++--
.../org/apache/solr/search/SolrQueryParser.java | 2 +-
.../solr/search/facet/FacetFieldProcessor.java | 42 +-
.../facet/FacetFieldProcessorByArray.java | 4 +
.../FacetFieldProcessorByEnumTermsStream.java | 2 +-
.../apache/solr/search/facet/FacetModule.java | 127 ++-
.../solr/search/facet/FacetProcessor.java | 27 +-
.../apache/solr/search/facet/FacetQuery.java | 6 +-
.../apache/solr/search/facet/FacetRange.java | 12 +-
.../apache/solr/search/facet/FacetRequest.java | 3 +
.../SearchGroupShardResponseProcessor.java | 2 +-
.../security/AutorizationEditOperation.java | 2 +-
.../org/apache/solr/update/CommitTracker.java | 5 +
.../solr/update/DefaultSolrCoreState.java | 15 +-
.../solr/update/DirectUpdateHandler2.java | 53 +-
.../org/apache/solr/update/DocumentBuilder.java | 67 +-
.../apache/solr/update/HdfsTransactionLog.java | 50 +
.../org/apache/solr/update/SolrCoreState.java | 6 +
.../apache/solr/update/SolrIndexSplitter.java | 3 +-
.../org/apache/solr/update/SolrIndexWriter.java | 31 +-
.../org/apache/solr/update/TransactionLog.java | 50 +
.../org/apache/solr/update/UpdateCommand.java | 1 +
.../java/org/apache/solr/update/UpdateLog.java | 185 +++-
.../processor/AtomicUpdateDocumentMerger.java | 11 +-
.../processor/DistributedUpdateProcessor.java | 38 +-
.../TolerantUpdateProcessorFactory.java | 2 +-
.../org/apache/solr/util/DateMathParser.java | 2 +-
.../org/apache/solr/util/RedactionUtils.java | 51 +
.../org/apache/solr/util/SolrPluginUtils.java | 4 +-
.../org/apache/solr/util/TestInjection.java | 54 +
...entedPoolingHttpClientConnectionManager.java | 38 +-
.../org/apache/solr/util/stats/MetricUtils.java | 83 +-
.../collection1/conf/multiword-synonyms.txt | 13 +
.../solr/collection1/conf/schema-docValues.xml | 1 +
.../conf/schema-multiword-synonyms.xml | 50 +
.../solr/collection1/conf/schema-spatial.xml | 4 +
.../conf/schema-unifiedhighlight.xml | 4 +-
.../test-files/solr/collection1/conf/schema.xml | 15 +-
.../solrconfig-configurerecoverystrategy.xml | 28 +
.../conf/solrconfig-customrecoverystrategy.xml | 32 +
.../conf/solrconfig-managed-schema.xml | 27 +-
...nfig-uninvertdocvaluesmergepolicyfactory.xml | 38 +
.../solr/collection1/conf/synonyms.txt | 2 +
.../conf/schema.xml | 31 +
.../conf/solrconfig.xml | 48 +
.../solr/cloud/BasicDistributedZk2Test.java | 6 +
.../solr/cloud/BasicDistributedZkTest.java | 9 +-
.../cloud/ChaosMonkeyNothingIsSafeTest.java | 7 +
.../org/apache/solr/cloud/ForceLeaderTest.java | 6 +
.../apache/solr/cloud/HttpPartitionTest.java | 7 +
.../LeaderInitiatedRecoveryOnCommitTest.java | 7 +
.../solr/cloud/OnlyLeaderIndexesTest.java | 435 ++++++++
.../solr/cloud/RecoveryAfterSoftCommitTest.java | 7 +-
.../org/apache/solr/cloud/ShardSplitTest.java | 6 +
.../cloud/SharedFSAutoReplicaFailoverTest.java | 29 +
.../apache/solr/cloud/TestCloudRecovery.java | 16 +-
.../apache/solr/cloud/TestCollectionAPI.java | 6 +-
.../apache/solr/cloud/TestRandomFlRTGCloud.java | 2 +-
.../cloud/hdfs/HdfsBasicDistributedZkTest.java | 7 +-
.../core/ConfigureRecoveryStrategyTest.java | 112 ++
.../core/snapshots/TestSolrCloudSnapshots.java | 2 +-
.../core/snapshots/TestSolrCoreSnapshots.java | 2 +-
.../org/apache/solr/handler/TestSQLHandler.java | 31 +
.../solr/handler/admin/MetricsHandlerTest.java | 31 +-
.../admin/PropertiesRequestHandlerTest.java | 73 ++
.../highlight/TestUnifiedSolrHighlighter.java | 12 +-
.../index/UninvertDocValuesMergePolicyTest.java | 243 +++++
.../solr/rest/schema/TestBulkSchemaAPI.java | 72 +-
.../org/apache/solr/schema/PolyFieldTest.java | 40 +-
.../apache/solr/schema/SortableBinaryField.java | 3 +-
.../org/apache/solr/schema/TestPointFields.java | 161 +--
.../org/apache/solr/search/LargeFieldTest.java | 133 +++
.../solr/search/TestCollapseQParserPlugin.java | 2 +-
.../solr/search/TestExtendedDismaxParser.java | 1032 +++++++++++++-----
.../solr/search/TestMultiWordSynonyms.java | 100 ++
.../apache/solr/search/TestSolr4Spatial.java | 61 +-
.../solr/search/TestSolrFieldCacheMBean.java | 4 +-
.../apache/solr/search/TestSolrQueryParser.java | 565 ++++++++--
.../search/facet/TestJsonFacetRefinement.java | 94 ++
.../solr/search/mlt/CloudMLTQParserTest.java | 14 +-
.../solr/update/DirectUpdateHandlerTest.java | 18 +-
.../apache/solr/update/DocumentBuilderTest.java | 71 +-
.../solr/update/SolrIndexMetricsTest.java | 5 +-
.../solr/update/TestInPlaceUpdatesDistrib.java | 114 +-
.../update/TestInPlaceUpdatesStandalone.java | 27 +
.../update/processor/AtomicUpdatesTest.java | 3 +-
.../apache/solr/util/stats/MetricUtilsTest.java | 53 +-
solr/server/scripts/cloud-scripts/zkcli.bat | 2 +-
solr/server/scripts/cloud-scripts/zkcli.sh | 2 +-
.../basic_configs/conf/managed-schema | 76 +-
.../conf/managed-schema | 73 +-
.../conf/managed-schema | 92 +-
.../conf/solrconfig.xml | 2 +-
.../solr/client/solrj/impl/CloudSolrClient.java | 17 +-
.../org/apache/solr/client/solrj/io/Tuple.java | 21 +-
.../client/solrj/io/eval/EqualsEvaluator.java | 2 +-
.../solrj/request/CollectionAdminRequest.java | 6 +
.../apache/solr/common/cloud/DocCollection.java | 14 +-
.../apache/solr/common/cloud/ZkStateReader.java | 1 +
.../solr/client/solrj/SolrExampleTests.java | 16 +-
.../client/solrj/impl/CloudSolrClientTest.java | 48 +
.../solr/common/params/SolrParamTest.java | 4 +-
.../java/org/apache/solr/SolrTestCaseJ4.java | 2 +-
.../cloud/AbstractFullDistribZkTestBase.java | 14 +-
solr/webapp/web/WEB-INF/web.xml | 2 +-
229 files changed, 10650 insertions(+), 4909 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/dev-tools/scripts/buildAndPushRelease.py
----------------------------------------------------------------------
diff --git a/dev-tools/scripts/buildAndPushRelease.py b/dev-tools/scripts/buildAndPushRelease.py
index d742214..57f093b 100644
--- a/dev-tools/scripts/buildAndPushRelease.py
+++ b/dev-tools/scripts/buildAndPushRelease.py
@@ -22,6 +22,8 @@ import os
import sys
import subprocess
import textwrap
+import urllib.request, urllib.error, urllib.parse
+import xml.etree.ElementTree as ET
LOG = '/tmp/release.log'
@@ -57,6 +59,14 @@ def runAndSendGPGPassword(command, password):
print(msg)
raise RuntimeError(msg)
+def load(urlString):
+ try:
+ content = urllib.request.urlopen(urlString).read().decode('utf-8')
+ except Exception as e:
+ print('Retrying download of url %s after exception: %s' % (urlString, e))
+ content = urllib.request.urlopen(urlString).read().decode('utf-8')
+ return content
+
def getGitRev():
status = os.popen('git status').read().strip()
if 'nothing to commit, working directory clean' not in status and 'nothing to commit, working tree clean' not in status:
@@ -84,6 +94,9 @@ def prepare(root, version, gpgKeyID, gpgPassword):
print(' git rev: %s' % rev)
log('\nGIT rev: %s\n' % rev)
+ print(' Check DOAP files')
+ checkDOAPfiles(version)
+
print(' ant clean test')
run('ant clean test')
@@ -119,6 +132,57 @@ def prepare(root, version, gpgKeyID, gpgPassword):
print()
return rev
+reVersion1 = re.compile(r'\>(\d+)\.(\d+)\.(\d+)(-alpha|-beta)?/\<', re.IGNORECASE)
+reVersion2 = re.compile(r'-(\d+)\.(\d+)\.(\d+)(-alpha|-beta)?\.zip<', re.IGNORECASE)
+reDoapRevision = re.compile(r'(\d+)\.(\d+)(?:\.(\d+))?(-alpha|-beta)?', re.IGNORECASE)
+def checkDOAPfiles(version):
+ # In Lucene and Solr DOAP files, verify presence of all releases less than the one being produced.
+ errorMessages = []
+ for product in 'lucene', 'solr':
+ url = 'https://archive.apache.org/dist/lucene/%s' % ('java' if product == 'lucene' else product)
+ distpage = load(url)
+ releases = set()
+ for regex in reVersion1, reVersion2:
+ for tup in regex.findall(distpage):
+ if tup[0] in ('1', '2'): # Ignore 1.X and 2.X releases
+ continue
+ releases.add(normalizeVersion(tup))
+ doapNS = '{http://usefulinc.com/ns/doap#}'
+ xpathRevision = '{0}Project/{0}release/{0}Version/{0}revision'.format(doapNS)
+ doapFile = "dev-tools/doap/%s.rdf" % product
+ treeRoot = ET.parse(doapFile).getroot()
+ doapRevisions = set()
+ for revision in treeRoot.findall(xpathRevision):
+ match = reDoapRevision.match(revision.text)
+ if (match is not None):
+ if (match.group(1) not in ('0', '1', '2')): # Ignore 0.X, 1.X and 2.X revisions
+ doapRevisions.add(normalizeVersion(match.groups()))
+ else:
+ errorMessages.append('ERROR: Failed to parse revision: %s in %s' % (revision.text, doapFile))
+ missingDoapRevisions = set()
+ for release in releases:
+ if release not in doapRevisions and release < version: # Ignore releases greater than the one being produced
+ missingDoapRevisions.add(release)
+ if len(missingDoapRevisions) > 0:
+ errorMessages.append('ERROR: Missing revision(s) in %s: %s' % (doapFile, ', '.join(sorted(missingDoapRevisions))))
+ if (len(errorMessages) > 0):
+ raise RuntimeError('\n%s\n(Hint: copy/paste from the stable branch version of the file(s).)'
+ % '\n'.join(errorMessages))
+
+def normalizeVersion(tup):
+ suffix = ''
+ if tup[-1] is not None and tup[-1].lower() == '-alpha':
+ tup = tup[:(len(tup) - 1)]
+ suffix = '-ALPHA'
+ elif tup[-1] is not None and tup[-1].lower() == '-beta':
+ tup = tup[:(len(tup) - 1)]
+ suffix = '-BETA'
+ while tup[-1] in ('', None):
+ tup = tup[:(len(tup) - 1)]
+ while len(tup) < 3:
+ tup = tup + ('0',)
+ return '.'.join(tup) + suffix
+
def pushLocal(version, root, rev, rcNum, localDir):
print('Push local [%s]...' % localDir)
os.makedirs(localDir)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/dev-tools/scripts/smokeTestRelease.py
----------------------------------------------------------------------
diff --git a/dev-tools/scripts/smokeTestRelease.py b/dev-tools/scripts/smokeTestRelease.py
index b0e76e9..9de490a 100644
--- a/dev-tools/scripts/smokeTestRelease.py
+++ b/dev-tools/scripts/smokeTestRelease.py
@@ -856,7 +856,7 @@ def testSolrExample(unpackPath, javaPath, isSrc):
print('FAILED: response is:\n%s' % s)
raise RuntimeError('query on solr example instance failed')
s = load('http://localhost:8983/v2/cores')
- if s.find('"responseHeader":{"status":0,"QTime":1}') == -1:
+ if s.find('"responseHeader":{"status":0') == -1:
print('FAILED: response is:\n%s' % s)
raise RuntimeError('query api v2 on solr example instance failed')
finally:
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 9407dfa..15f4ff3 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -80,10 +80,17 @@ Other
* LUCENE-7681: MemoryIndex uses new DocValues API (Alan Woodward)
+======================= Lucene 6.6.0 =======================
+(No Changes)
+
======================= Lucene 6.5.0 =======================
API Changes
+* LUCENE-7740: Refactor Range Fields to remove Field suffix (e.g., DoubleRange),
+ move InetAddressRange and InetAddressPoint from sandbox to misc module, and
+ refactor all other range fields from sandbox to core. (Nick Knize)
+
* LUCENE-7624: TermsQuery has been renamed as TermInSetQuery and moved to core.
(Alan Woodward)
@@ -131,6 +138,9 @@ API Changes
New Features
+* LUCENE-7738: Add new InetAddressRange for indexing and querying InetAddress
+ ranges. (Nick Knize)
+
* LUCENE-7449: Add CROSSES relation support to RangeFieldQuery. (Nick Knize)
* LUCENE-7623: Add FunctionScoreQuery and FunctionMatchQuery (Alan Woodward,
@@ -219,6 +229,9 @@ Improvements
* LUCENE-7695: ComplexPhraseQueryParser to support query time synonyms (Markus Jelsma
via Mikhail Khludnev)
+* LUCENE-7747: QueryBuilder now iterates lazily over the possible paths when building a graph query
+ (Jim Ferenczi)
+
Optimizations
* LUCENE-7641: Optimized point range queries to compute documents that do not
@@ -249,6 +262,13 @@ Optimizations
* LUCENE-7699: Query parsers now use span queries to produce more efficient
phrase queries for multi-token synonyms. (Matt Webber via Jim Ferenczi)
+* LUCENE-7742: Fix places where we were unboxing and then re-boxing
+ according to FindBugs (Daniel Jelinski via Mike McCandless)
+
+* LUCENE-7739: Fix places where we unnecessarily boxed while parsing
+ a numeric value according to FindBugs (Daniel Jelinski via Mike
+ McCandless)
+
Build
* LUCENE-7653: Update randomizedtesting to version 2.5.0. (Dawid Weiss)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/feeds/EnwikiContentSource.java
----------------------------------------------------------------------
diff --git a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/feeds/EnwikiContentSource.java b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/feeds/EnwikiContentSource.java
index a933e56..7258476 100644
--- a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/feeds/EnwikiContentSource.java
+++ b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/feeds/EnwikiContentSource.java
@@ -101,7 +101,7 @@ public class EnwikiContentSource extends ContentSource {
buffer.append(original.substring(8, 10));
buffer.append('-');
- buffer.append(months[Integer.valueOf(original.substring(5, 7)).intValue() - 1]);
+ buffer.append(months[Integer.parseInt(original.substring(5, 7)) - 1]);
buffer.append('-');
buffer.append(original.substring(0, 4));
buffer.append(' ');
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ForceMergeTask.java
----------------------------------------------------------------------
diff --git a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ForceMergeTask.java b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ForceMergeTask.java
index 40a3637..292642f 100644
--- a/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ForceMergeTask.java
+++ b/lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ForceMergeTask.java
@@ -46,7 +46,7 @@ public class ForceMergeTask extends PerfTask {
@Override
public void setParams(String params) {
super.setParams(params);
- maxNumSegments = Double.valueOf(params).intValue();
+ maxNumSegments = (int)Double.parseDouble(params);
}
@Override
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/core/src/java/org/apache/lucene/document/DoubleRange.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/DoubleRange.java b/lucene/core/src/java/org/apache/lucene/document/DoubleRange.java
new file mode 100644
index 0000000..90a8eb9
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/document/DoubleRange.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.document;
+
+import org.apache.lucene.document.RangeFieldQuery.QueryType;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+
+/**
+ * An indexed Double Range field.
+ * <p>
+ * This field indexes dimensional ranges defined as min/max pairs. It supports
+ * up to a maximum of 4 dimensions (indexed as 8 numeric values). With 1 dimension representing a single double range,
+ * 2 dimensions representing a bounding box, 3 dimensions a bounding cube, and 4 dimensions a tesseract.
+ * <p>
+ * Multiple values for the same field in one document is supported, and open ended ranges can be defined using
+ * {@code Double.NEGATIVE_INFINITY} and {@code Double.POSITIVE_INFINITY}.
+ *
+ * <p>
+ * This field defines the following static factory methods for common search operations over double ranges:
+ * <ul>
+ * <li>{@link #newIntersectsQuery newIntersectsQuery()} matches ranges that intersect the defined search range.
+ * <li>{@link #newWithinQuery newWithinQuery()} matches ranges that are within the defined search range.
+ * <li>{@link #newContainsQuery newContainsQuery()} matches ranges that contain the defined search range.
+ * </ul>
+ */
+public class DoubleRange extends Field {
+ /** stores double values so number of bytes is 8 */
+ public static final int BYTES = Double.BYTES;
+
+ /**
+ * Create a new DoubleRange type, from min/max parallel arrays
+ *
+ * @param name field name. must not be null.
+ * @param min range min values; each entry is the min value for the dimension
+ * @param max range max values; each entry is the max value for the dimension
+ */
+ public DoubleRange(String name, final double[] min, final double[] max) {
+ super(name, getType(min.length));
+ setRangeValues(min, max);
+ }
+
+ /** set the field type */
+ private static FieldType getType(int dimensions) {
+ if (dimensions > 4) {
+ throw new IllegalArgumentException("DoubleRange does not support greater than 4 dimensions");
+ }
+
+ FieldType ft = new FieldType();
+ // dimensions is set as 2*dimension size (min/max per dimension)
+ ft.setDimensions(dimensions*2, BYTES);
+ ft.freeze();
+ return ft;
+ }
+
+ /**
+ * Changes the values of the field.
+ * @param min array of min values. (accepts {@code Double.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Double.POSITIVE_INFINITY})
+ * @throws IllegalArgumentException if {@code min} or {@code max} is invalid
+ */
+ public void setRangeValues(double[] min, double[] max) {
+ checkArgs(min, max);
+ if (min.length*2 != type.pointDimensionCount() || max.length*2 != type.pointDimensionCount()) {
+ throw new IllegalArgumentException("field (name=" + name + ") uses " + type.pointDimensionCount()/2
+ + " dimensions; cannot change to (incoming) " + min.length + " dimensions");
+ }
+
+ final byte[] bytes;
+ if (fieldsData == null) {
+ bytes = new byte[BYTES*2*min.length];
+ fieldsData = new BytesRef(bytes);
+ } else {
+ bytes = ((BytesRef)fieldsData).bytes;
+ }
+ verifyAndEncode(min, max, bytes);
+ }
+
+ /** validate the arguments */
+ private static void checkArgs(final double[] min, final double[] max) {
+ if (min == null || max == null || min.length == 0 || max.length == 0) {
+ throw new IllegalArgumentException("min/max range values cannot be null or empty");
+ }
+ if (min.length != max.length) {
+ throw new IllegalArgumentException("min/max ranges must agree");
+ }
+ if (min.length > 4) {
+ throw new IllegalArgumentException("DoubleRange does not support greater than 4 dimensions");
+ }
+ }
+
+ /**
+ * Encodes the min, max ranges into a byte array
+ */
+ private static byte[] encode(double[] min, double[] max) {
+ checkArgs(min, max);
+ byte[] b = new byte[BYTES*2*min.length];
+ verifyAndEncode(min, max, b);
+ return b;
+ }
+
+ /**
+ * encode the ranges into a sortable byte array ({@code Double.NaN} not allowed)
+ * <p>
+ * example for 4 dimensions (8 bytes per dimension value):
+ * minD1 ... minD4 | maxD1 ... maxD4
+ */
+ static void verifyAndEncode(double[] min, double[] max, byte[] bytes) {
+ for (int d=0,i=0,j=min.length*BYTES; d<min.length; ++d, i+=BYTES, j+=BYTES) {
+ if (Double.isNaN(min[d])) {
+ throw new IllegalArgumentException("invalid min value (" + Double.NaN + ")" + " in DoubleRange");
+ }
+ if (Double.isNaN(max[d])) {
+ throw new IllegalArgumentException("invalid max value (" + Double.NaN + ")" + " in DoubleRange");
+ }
+ if (min[d] > max[d]) {
+ throw new IllegalArgumentException("min value (" + min[d] + ") is greater than max value (" + max[d] + ")");
+ }
+ encode(min[d], bytes, i);
+ encode(max[d], bytes, j);
+ }
+ }
+
+ /** encode the given value into the byte array at the defined offset */
+ private static void encode(double val, byte[] bytes, int offset) {
+ NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(val), bytes, offset);
+ }
+
+ /**
+ * Get the min value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded min value
+ */
+ public double getMin(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMin(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /**
+ * Get the max value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded max value
+ */
+ public double getMax(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMax(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /** decodes the min value (for the defined dimension) from the encoded input byte array */
+ static double decodeMin(byte[] b, int dimension) {
+ int offset = dimension*BYTES;
+ return NumericUtils.sortableLongToDouble(NumericUtils.sortableBytesToLong(b, offset));
+ }
+
+ /** decodes the max value (for the defined dimension) from the encoded input byte array */
+ static double decodeMax(byte[] b, int dimension) {
+ int offset = b.length/2 + dimension*BYTES;
+ return NumericUtils.sortableLongToDouble(NumericUtils.sortableBytesToLong(b, offset));
+ }
+
+ /**
+ * Create a query for matching indexed ranges that intersect the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Double.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Double.POSITIVE_INFINITY})
+ * @return query for matching intersecting ranges (overlap, within, or contains)
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newIntersectsQuery(String field, final double[] min, final double[] max) {
+ return newRelationQuery(field, min, max, QueryType.INTERSECTS);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that contain the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Double.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Double.MAX_VALUE})
+ * @return query for matching ranges that contain the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newContainsQuery(String field, final double[] min, final double[] max) {
+ return newRelationQuery(field, min, max, QueryType.CONTAINS);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that are within the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Double.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Double.MAX_VALUE})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newWithinQuery(String field, final double[] min, final double[] max) {
+ return newRelationQuery(field, min, max, QueryType.WITHIN);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that cross the defined range.
+ * A CROSSES is defined as any set of ranges that are not disjoint and not wholly contained by
+ * the query. Effectively, its the complement of union(WITHIN, DISJOINT).
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Double.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Double.MAX_VALUE})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newCrossesQuery(String field, final double[] min, final double[] max) {
+ return newRelationQuery(field, min, max, QueryType.CROSSES);
+ }
+
+ /** helper method for creating the desired relational query */
+ private static Query newRelationQuery(String field, final double[] min, final double[] max, QueryType relation) {
+ checkArgs(min, max);
+ return new RangeFieldQuery(field, encode(min, max), min.length, relation) {
+ @Override
+ protected String toString(byte[] ranges, int dimension) {
+ return DoubleRange.toString(ranges, dimension);
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" <");
+ sb.append(name);
+ sb.append(':');
+ byte[] b = ((BytesRef)fieldsData).bytes;
+ toString(b, 0);
+ for (int d=1; d<type.pointDimensionCount(); ++d) {
+ sb.append(' ');
+ toString(b, d);
+ }
+ sb.append('>');
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the String representation for the range at the given dimension
+ * @param ranges the encoded ranges, never null
+ * @param dimension the dimension of interest
+ * @return The string representation for the range at the provided dimension
+ */
+ private static String toString(byte[] ranges, int dimension) {
+ return "[" + Double.toString(decodeMin(ranges, dimension)) + " : "
+ + Double.toString(decodeMax(ranges, dimension)) + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/core/src/java/org/apache/lucene/document/FloatRange.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/FloatRange.java b/lucene/core/src/java/org/apache/lucene/document/FloatRange.java
new file mode 100644
index 0000000..8b40538
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/document/FloatRange.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.document;
+
+import org.apache.lucene.document.RangeFieldQuery.QueryType;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+
+/**
+ * An indexed Float Range field.
+ * <p>
+ * This field indexes dimensional ranges defined as min/max pairs. It supports
+ * up to a maximum of 4 dimensions (indexed as 8 numeric values). With 1 dimension representing a single float range,
+ * 2 dimensions representing a bounding box, 3 dimensions a bounding cube, and 4 dimensions a tesseract.
+ * <p>
+ * Multiple values for the same field in one document is supported, and open ended ranges can be defined using
+ * {@code Float.NEGATIVE_INFINITY} and {@code Float.POSITIVE_INFINITY}.
+ *
+ * <p>
+ * This field defines the following static factory methods for common search operations over float ranges:
+ * <ul>
+ * <li>{@link #newIntersectsQuery newIntersectsQuery()} matches ranges that intersect the defined search range.
+ * <li>{@link #newWithinQuery newWithinQuery()} matches ranges that are within the defined search range.
+ * <li>{@link #newContainsQuery newContainsQuery()} matches ranges that contain the defined search range.
+ * </ul>
+ */
+public class FloatRange extends Field {
+ /** stores float values so number of bytes is 4 */
+ public static final int BYTES = Float.BYTES;
+
+ /**
+ * Create a new FloatRange type, from min/max parallel arrays
+ *
+ * @param name field name. must not be null.
+ * @param min range min values; each entry is the min value for the dimension
+ * @param max range max values; each entry is the max value for the dimension
+ */
+ public FloatRange(String name, final float[] min, final float[] max) {
+ super(name, getType(min.length));
+ setRangeValues(min, max);
+ }
+
+ /** set the field type */
+ private static FieldType getType(int dimensions) {
+ if (dimensions > 4) {
+ throw new IllegalArgumentException("FloatRange does not support greater than 4 dimensions");
+ }
+
+ FieldType ft = new FieldType();
+ // dimensions is set as 2*dimension size (min/max per dimension)
+ ft.setDimensions(dimensions*2, BYTES);
+ ft.freeze();
+ return ft;
+ }
+
+ /**
+ * Changes the values of the field.
+ * @param min array of min values. (accepts {@code Float.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Float.POSITIVE_INFINITY})
+ * @throws IllegalArgumentException if {@code min} or {@code max} is invalid
+ */
+ public void setRangeValues(float[] min, float[] max) {
+ checkArgs(min, max);
+ if (min.length*2 != type.pointDimensionCount() || max.length*2 != type.pointDimensionCount()) {
+ throw new IllegalArgumentException("field (name=" + name + ") uses " + type.pointDimensionCount()/2
+ + " dimensions; cannot change to (incoming) " + min.length + " dimensions");
+ }
+
+ final byte[] bytes;
+ if (fieldsData == null) {
+ bytes = new byte[BYTES*2*min.length];
+ fieldsData = new BytesRef(bytes);
+ } else {
+ bytes = ((BytesRef)fieldsData).bytes;
+ }
+ verifyAndEncode(min, max, bytes);
+ }
+
+ /** validate the arguments */
+ private static void checkArgs(final float[] min, final float[] max) {
+ if (min == null || max == null || min.length == 0 || max.length == 0) {
+ throw new IllegalArgumentException("min/max range values cannot be null or empty");
+ }
+ if (min.length != max.length) {
+ throw new IllegalArgumentException("min/max ranges must agree");
+ }
+ if (min.length > 4) {
+ throw new IllegalArgumentException("FloatRange does not support greater than 4 dimensions");
+ }
+ }
+
+ /**
+ * Encodes the min, max ranges into a byte array
+ */
+ private static byte[] encode(float[] min, float[] max) {
+ checkArgs(min, max);
+ byte[] b = new byte[BYTES*2*min.length];
+ verifyAndEncode(min, max, b);
+ return b;
+ }
+
+ /**
+ * encode the ranges into a sortable byte array ({@code Float.NaN} not allowed)
+ * <p>
+ * example for 4 dimensions (8 bytes per dimension value):
+ * minD1 ... minD4 | maxD1 ... maxD4
+ */
+ static void verifyAndEncode(float[] min, float[] max, byte[] bytes) {
+ for (int d=0,i=0,j=min.length*BYTES; d<min.length; ++d, i+=BYTES, j+=BYTES) {
+ if (Double.isNaN(min[d])) {
+ throw new IllegalArgumentException("invalid min value (" + Float.NaN + ")" + " in FloatRange");
+ }
+ if (Double.isNaN(max[d])) {
+ throw new IllegalArgumentException("invalid max value (" + Float.NaN + ")" + " in FloatRange");
+ }
+ if (min[d] > max[d]) {
+ throw new IllegalArgumentException("min value (" + min[d] + ") is greater than max value (" + max[d] + ")");
+ }
+ encode(min[d], bytes, i);
+ encode(max[d], bytes, j);
+ }
+ }
+
+ /** encode the given value into the byte array at the defined offset */
+ private static void encode(float val, byte[] bytes, int offset) {
+ NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(val), bytes, offset);
+ }
+
+ /**
+ * Get the min value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded min value
+ */
+ public float getMin(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMin(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /**
+ * Get the max value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded max value
+ */
+ public float getMax(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMax(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /** decodes the min value (for the defined dimension) from the encoded input byte array */
+ static float decodeMin(byte[] b, int dimension) {
+ int offset = dimension*BYTES;
+ return NumericUtils.sortableIntToFloat(NumericUtils.sortableBytesToInt(b, offset));
+ }
+
+ /** decodes the max value (for the defined dimension) from the encoded input byte array */
+ static float decodeMax(byte[] b, int dimension) {
+ int offset = b.length/2 + dimension*BYTES;
+ return NumericUtils.sortableIntToFloat(NumericUtils.sortableBytesToInt(b, offset));
+ }
+
+ /**
+ * Create a query for matching indexed ranges that intersect the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Float.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Float.MAX_VALUE})
+ * @return query for matching intersecting ranges (overlap, within, or contains)
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newIntersectsQuery(String field, final float[] min, final float[] max) {
+ return newRelationQuery(field, min, max, QueryType.INTERSECTS);
+ }
+
+ /**
+ * Create a query for matching indexed float ranges that contain the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Float.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Float.POSITIVE_INFINITY})
+ * @return query for matching ranges that contain the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newContainsQuery(String field, final float[] min, final float[] max) {
+ return newRelationQuery(field, min, max, QueryType.CONTAINS);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that are within the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Float.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Float.POSITIVE_INFINITY})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newWithinQuery(String field, final float[] min, final float[] max) {
+ return newRelationQuery(field, min, max, QueryType.WITHIN);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that cross the defined range.
+ * A CROSSES is defined as any set of ranges that are not disjoint and not wholly contained by
+ * the query. Effectively, its the complement of union(WITHIN, DISJOINT).
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Float.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Float.POSITIVE_INFINITY})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newCrossesQuery(String field, final float[] min, final float[] max) {
+ return newRelationQuery(field, min, max, QueryType.CROSSES);
+ }
+
+ /** helper method for creating the desired relational query */
+ private static Query newRelationQuery(String field, final float[] min, final float[] max, QueryType relation) {
+ checkArgs(min, max);
+ return new RangeFieldQuery(field, encode(min, max), min.length, relation) {
+ @Override
+ protected String toString(byte[] ranges, int dimension) {
+ return FloatRange.toString(ranges, dimension);
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" <");
+ sb.append(name);
+ sb.append(':');
+ byte[] b = ((BytesRef)fieldsData).bytes;
+ toString(b, 0);
+ for (int d=1; d<type.pointDimensionCount(); ++d) {
+ sb.append(' ');
+ toString(b, d);
+ }
+ sb.append('>');
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the String representation for the range at the given dimension
+ * @param ranges the encoded ranges, never null
+ * @param dimension the dimension of interest
+ * @return The string representation for the range at the provided dimension
+ */
+ private static String toString(byte[] ranges, int dimension) {
+ return "[" + Float.toString(decodeMin(ranges, dimension)) + " : "
+ + Float.toString(decodeMax(ranges, dimension)) + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/core/src/java/org/apache/lucene/document/IntRange.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/IntRange.java b/lucene/core/src/java/org/apache/lucene/document/IntRange.java
new file mode 100644
index 0000000..6d2b71c
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/document/IntRange.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.document;
+
+import org.apache.lucene.document.RangeFieldQuery.QueryType;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+
+/**
+ * An indexed Integer Range field.
+ * <p>
+ * This field indexes dimensional ranges defined as min/max pairs. It supports
+ * up to a maximum of 4 dimensions (indexed as 8 numeric values). With 1 dimension representing a single integer range,
+ * 2 dimensions representing a bounding box, 3 dimensions a bounding cube, and 4 dimensions a tesseract.
+ * <p>
+ * Multiple values for the same field in one document is supported, and open ended ranges can be defined using
+ * {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE}.
+ *
+ * <p>
+ * This field defines the following static factory methods for common search operations over integer ranges:
+ * <ul>
+ * <li>{@link #newIntersectsQuery newIntersectsQuery()} matches ranges that intersect the defined search range.
+ * <li>{@link #newWithinQuery newWithinQuery()} matches ranges that are within the defined search range.
+ * <li>{@link #newContainsQuery newContainsQuery()} matches ranges that contain the defined search range.
+ * </ul>
+ */
+public class IntRange extends Field {
+ /** stores integer values so number of bytes is 4 */
+ public static final int BYTES = Integer.BYTES;
+
+ /**
+ * Create a new IntRange type, from min/max parallel arrays
+ *
+ * @param name field name. must not be null.
+ * @param min range min values; each entry is the min value for the dimension
+ * @param max range max values; each entry is the max value for the dimension
+ */
+ public IntRange(String name, final int[] min, final int[] max) {
+ super(name, getType(min.length));
+ setRangeValues(min, max);
+ }
+
+ /** set the field type */
+ private static FieldType getType(int dimensions) {
+ if (dimensions > 4) {
+ throw new IllegalArgumentException("IntRange does not support greater than 4 dimensions");
+ }
+
+ FieldType ft = new FieldType();
+ // dimensions is set as 2*dimension size (min/max per dimension)
+ ft.setDimensions(dimensions*2, BYTES);
+ ft.freeze();
+ return ft;
+ }
+
+ /**
+ * Changes the values of the field.
+ * @param min array of min values. (accepts {@code Integer.NEGATIVE_INFINITY})
+ * @param max array of max values. (accepts {@code Integer.POSITIVE_INFINITY})
+ * @throws IllegalArgumentException if {@code min} or {@code max} is invalid
+ */
+ public void setRangeValues(int[] min, int[] max) {
+ checkArgs(min, max);
+ if (min.length*2 != type.pointDimensionCount() || max.length*2 != type.pointDimensionCount()) {
+ throw new IllegalArgumentException("field (name=" + name + ") uses " + type.pointDimensionCount()/2
+ + " dimensions; cannot change to (incoming) " + min.length + " dimensions");
+ }
+
+ final byte[] bytes;
+ if (fieldsData == null) {
+ bytes = new byte[BYTES*2*min.length];
+ fieldsData = new BytesRef(bytes);
+ } else {
+ bytes = ((BytesRef)fieldsData).bytes;
+ }
+ verifyAndEncode(min, max, bytes);
+ }
+
+ /** validate the arguments */
+ private static void checkArgs(final int[] min, final int[] max) {
+ if (min == null || max == null || min.length == 0 || max.length == 0) {
+ throw new IllegalArgumentException("min/max range values cannot be null or empty");
+ }
+ if (min.length != max.length) {
+ throw new IllegalArgumentException("min/max ranges must agree");
+ }
+ if (min.length > 4) {
+ throw new IllegalArgumentException("IntRange does not support greater than 4 dimensions");
+ }
+ }
+
+ /**
+ * Encodes the min, max ranges into a byte array
+ */
+ private static byte[] encode(int[] min, int[] max) {
+ checkArgs(min, max);
+ byte[] b = new byte[BYTES*2*min.length];
+ verifyAndEncode(min, max, b);
+ return b;
+ }
+
+ /**
+ * encode the ranges into a sortable byte array ({@code Double.NaN} not allowed)
+ * <p>
+ * example for 4 dimensions (8 bytes per dimension value):
+ * minD1 ... minD4 | maxD1 ... maxD4
+ */
+ static void verifyAndEncode(int[] min, int[] max, byte[] bytes) {
+ for (int d=0,i=0,j=min.length*BYTES; d<min.length; ++d, i+=BYTES, j+=BYTES) {
+ if (Double.isNaN(min[d])) {
+ throw new IllegalArgumentException("invalid min value (" + Double.NaN + ")" + " in IntRange");
+ }
+ if (Double.isNaN(max[d])) {
+ throw new IllegalArgumentException("invalid max value (" + Double.NaN + ")" + " in IntRange");
+ }
+ if (min[d] > max[d]) {
+ throw new IllegalArgumentException("min value (" + min[d] + ") is greater than max value (" + max[d] + ")");
+ }
+ encode(min[d], bytes, i);
+ encode(max[d], bytes, j);
+ }
+ }
+
+ /** encode the given value into the byte array at the defined offset */
+ private static void encode(int val, byte[] bytes, int offset) {
+ NumericUtils.intToSortableBytes(val, bytes, offset);
+ }
+
+ /**
+ * Get the min value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded min value
+ */
+ public int getMin(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMin(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /**
+ * Get the max value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded max value
+ */
+ public int getMax(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMax(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /** decodes the min value (for the defined dimension) from the encoded input byte array */
+ static int decodeMin(byte[] b, int dimension) {
+ int offset = dimension*BYTES;
+ return NumericUtils.sortableBytesToInt(b, offset);
+ }
+
+ /** decodes the max value (for the defined dimension) from the encoded input byte array */
+ static int decodeMax(byte[] b, int dimension) {
+ int offset = b.length/2 + dimension*BYTES;
+ return NumericUtils.sortableBytesToInt(b, offset);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that intersect the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Integer.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Integer.MAX_VALUE})
+ * @return query for matching intersecting ranges (overlap, within, or contains)
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newIntersectsQuery(String field, final int[] min, final int[] max) {
+ return newRelationQuery(field, min, max, QueryType.INTERSECTS);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that contain the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Integer.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Integer.MAX_VALUE})
+ * @return query for matching ranges that contain the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newContainsQuery(String field, final int[] min, final int[] max) {
+ return newRelationQuery(field, min, max, QueryType.CONTAINS);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that are within the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Integer.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Integer.MAX_VALUE})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newWithinQuery(String field, final int[] min, final int[] max) {
+ return newRelationQuery(field, min, max, QueryType.WITHIN);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that cross the defined range.
+ * A CROSSES is defined as any set of ranges that are not disjoint and not wholly contained by
+ * the query. Effectively, its the complement of union(WITHIN, DISJOINT).
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Integer.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Integer.MAX_VALUE})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newCrossesQuery(String field, final int[] min, final int[] max) {
+ return newRelationQuery(field, min, max, QueryType.CROSSES);
+ }
+
+ /** helper method for creating the desired relational query */
+ private static Query newRelationQuery(String field, final int[] min, final int[] max, QueryType relation) {
+ checkArgs(min, max);
+ return new RangeFieldQuery(field, encode(min, max), min.length, relation) {
+ @Override
+ protected String toString(byte[] ranges, int dimension) {
+ return IntRange.toString(ranges, dimension);
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" <");
+ sb.append(name);
+ sb.append(':');
+ byte[] b = ((BytesRef)fieldsData).bytes;
+ toString(b, 0);
+ for (int d=1; d<type.pointDimensionCount(); ++d) {
+ sb.append(' ');
+ toString(b, d);
+ }
+ sb.append('>');
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the String representation for the range at the given dimension
+ * @param ranges the encoded ranges, never null
+ * @param dimension the dimension of interest
+ * @return The string representation for the range at the provided dimension
+ */
+ private static String toString(byte[] ranges, int dimension) {
+ return "[" + Integer.toString(decodeMin(ranges, dimension)) + " : "
+ + Integer.toString(decodeMax(ranges, dimension)) + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/core/src/java/org/apache/lucene/document/LongRange.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/LongRange.java b/lucene/core/src/java/org/apache/lucene/document/LongRange.java
new file mode 100644
index 0000000..009f4a1
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/document/LongRange.java
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.document;
+
+import org.apache.lucene.document.RangeFieldQuery.QueryType;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+
+/**
+ * An indexed Long Range field.
+ * <p>
+ * This field indexes dimensional ranges defined as min/max pairs. It supports
+ * up to a maximum of 4 dimensions (indexed as 8 numeric values). With 1 dimension representing a single long range,
+ * 2 dimensions representing a bounding box, 3 dimensions a bounding cube, and 4 dimensions a tesseract.
+ * <p>
+ * Multiple values for the same field in one document is supported, and open ended ranges can be defined using
+ * {@code Long.MIN_VALUE} and {@code Long.MAX_VALUE}.
+ *
+ * <p>
+ * This field defines the following static factory methods for common search operations over long ranges:
+ * <ul>
+ * <li>{@link #newIntersectsQuery newIntersectsQuery()} matches ranges that intersect the defined search range.
+ * <li>{@link #newWithinQuery newWithinQuery()} matches ranges that are within the defined search range.
+ * <li>{@link #newContainsQuery newContainsQuery()} matches ranges that contain the defined search range.
+ * </ul>
+ */
+public class LongRange extends Field {
+ /** stores long values so number of bytes is 8 */
+ public static final int BYTES = Long.BYTES;
+
+ /**
+ * Create a new LongRange type, from min/max parallel arrays
+ *
+ * @param name field name. must not be null.
+ * @param min range min values; each entry is the min value for the dimension
+ * @param max range max values; each entry is the max value for the dimension
+ */
+ public LongRange(String name, final long[] min, final long[] max) {
+ super(name, getType(min.length));
+ setRangeValues(min, max);
+ }
+
+ /** set the field type */
+ private static FieldType getType(int dimensions) {
+ if (dimensions > 4) {
+ throw new IllegalArgumentException("LongRange does not support greater than 4 dimensions");
+ }
+
+ FieldType ft = new FieldType();
+ // dimensions is set as 2*dimension size (min/max per dimension)
+ ft.setDimensions(dimensions*2, BYTES);
+ ft.freeze();
+ return ft;
+ }
+
+ /**
+ * Changes the values of the field.
+ * @param min array of min values. (accepts {@code Long.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Long.MAX_VALUE})
+ * @throws IllegalArgumentException if {@code min} or {@code max} is invalid
+ */
+ public void setRangeValues(long[] min, long[] max) {
+ checkArgs(min, max);
+ if (min.length*2 != type.pointDimensionCount() || max.length*2 != type.pointDimensionCount()) {
+ throw new IllegalArgumentException("field (name=" + name + ") uses " + type.pointDimensionCount()/2
+ + " dimensions; cannot change to (incoming) " + min.length + " dimensions");
+ }
+
+ final byte[] bytes;
+ if (fieldsData == null) {
+ bytes = new byte[BYTES*2*min.length];
+ fieldsData = new BytesRef(bytes);
+ } else {
+ bytes = ((BytesRef)fieldsData).bytes;
+ }
+ verifyAndEncode(min, max, bytes);
+ }
+
+ /** validate the arguments */
+ private static void checkArgs(final long[] min, final long[] max) {
+ if (min == null || max == null || min.length == 0 || max.length == 0) {
+ throw new IllegalArgumentException("min/max range values cannot be null or empty");
+ }
+ if (min.length != max.length) {
+ throw new IllegalArgumentException("min/max ranges must agree");
+ }
+ if (min.length > 4) {
+ throw new IllegalArgumentException("LongRange does not support greater than 4 dimensions");
+ }
+ }
+
+ /** Encodes the min, max ranges into a byte array */
+ private static byte[] encode(long[] min, long[] max) {
+ checkArgs(min, max);
+ byte[] b = new byte[BYTES*2*min.length];
+ verifyAndEncode(min, max, b);
+ return b;
+ }
+
+ /**
+ * encode the ranges into a sortable byte array ({@code Double.NaN} not allowed)
+ * <p>
+ * example for 4 dimensions (8 bytes per dimension value):
+ * minD1 ... minD4 | maxD1 ... maxD4
+ */
+ static void verifyAndEncode(long[] min, long[] max, byte[] bytes) {
+ for (int d=0,i=0,j=min.length*BYTES; d<min.length; ++d, i+=BYTES, j+=BYTES) {
+ if (Double.isNaN(min[d])) {
+ throw new IllegalArgumentException("invalid min value (" + Double.NaN + ")" + " in LongRange");
+ }
+ if (Double.isNaN(max[d])) {
+ throw new IllegalArgumentException("invalid max value (" + Double.NaN + ")" + " in LongRange");
+ }
+ if (min[d] > max[d]) {
+ throw new IllegalArgumentException("min value (" + min[d] + ") is greater than max value (" + max[d] + ")");
+ }
+ encode(min[d], bytes, i);
+ encode(max[d], bytes, j);
+ }
+ }
+
+ /** encode the given value into the byte array at the defined offset */
+ private static void encode(long val, byte[] bytes, int offset) {
+ NumericUtils.longToSortableBytes(val, bytes, offset);
+ }
+
+ /**
+ * Get the min value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded min value
+ */
+ public long getMin(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMin(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /**
+ * Get the max value for the given dimension
+ * @param dimension the dimension, always positive
+ * @return the decoded max value
+ */
+ public long getMax(int dimension) {
+ if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
+ throw new IllegalArgumentException("dimension request (" + dimension +
+ ") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
+ }
+ return decodeMax(((BytesRef)fieldsData).bytes, dimension);
+ }
+
+ /** decodes the min value (for the defined dimension) from the encoded input byte array */
+ static long decodeMin(byte[] b, int dimension) {
+ int offset = dimension*BYTES;
+ return NumericUtils.sortableBytesToLong(b, offset);
+ }
+
+ /** decodes the max value (for the defined dimension) from the encoded input byte array */
+ static long decodeMax(byte[] b, int dimension) {
+ int offset = b.length/2 + dimension*BYTES;
+ return NumericUtils.sortableBytesToLong(b, offset);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that intersect the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Long.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Long.MAX_VALUE})
+ * @return query for matching intersecting ranges (overlap, within, or contains)
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newIntersectsQuery(String field, final long[] min, final long[] max) {
+ return newRelationQuery(field, min, max, QueryType.INTERSECTS);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that contain the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Long.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Long.MAX_VALUE})
+ * @return query for matching ranges that contain the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newContainsQuery(String field, final long[] min, final long[] max) {
+ return newRelationQuery(field, min, max, QueryType.CONTAINS);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that are within the defined range.
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Long.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Long.MAX_VALUE})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newWithinQuery(String field, final long[] min, final long[] max) {
+ return newRelationQuery(field, min, max, QueryType.WITHIN);
+ }
+
+ /**
+ * Create a query for matching indexed ranges that cross the defined range.
+ * A CROSSES is defined as any set of ranges that are not disjoint and not wholly contained by
+ * the query. Effectively, its the complement of union(WITHIN, DISJOINT).
+ * @param field field name. must not be null.
+ * @param min array of min values. (accepts {@code Long.MIN_VALUE})
+ * @param max array of max values. (accepts {@code Long.MAX_VALUE})
+ * @return query for matching ranges within the defined range
+ * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid
+ */
+ public static Query newCrossesQuery(String field, final long[] min, final long[] max) {
+ return newRelationQuery(field, min, max, QueryType.CROSSES);
+ }
+
+ /** helper method for creating the desired relational query */
+ private static Query newRelationQuery(String field, final long[] min, final long[] max, QueryType relation) {
+ checkArgs(min, max);
+ return new RangeFieldQuery(field, encode(min, max), min.length, relation) {
+ @Override
+ protected String toString(byte[] ranges, int dimension) {
+ return LongRange.toString(ranges, dimension);
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" <");
+ sb.append(name);
+ sb.append(':');
+ byte[] b = ((BytesRef)fieldsData).bytes;
+ toString(b, 0);
+ for (int d=1; d<type.pointDimensionCount(); ++d) {
+ sb.append(' ');
+ toString(b, d);
+ }
+ sb.append('>');
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the String representation for the range at the given dimension
+ * @param ranges the encoded ranges, never null
+ * @param dimension the dimension of interest
+ * @return The string representation for the range at the provided dimension
+ */
+ private static String toString(byte[] ranges, int dimension) {
+ return "[" + Long.toString(decodeMin(ranges, dimension)) + " : "
+ + Long.toString(decodeMax(ranges, dimension)) + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java
new file mode 100644
index 0000000..10f10fa
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java
@@ -0,0 +1,340 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.document;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.function.IntPredicate;
+import java.util.function.Predicate;
+
+import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.PointValues;
+import org.apache.lucene.index.PointValues.Relation;
+import org.apache.lucene.index.PointValues.IntersectVisitor;
+import org.apache.lucene.search.ConstantScoreScorer;
+import org.apache.lucene.search.ConstantScoreWeight;
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.util.DocIdSetBuilder;
+import org.apache.lucene.util.StringHelper;
+
+/**
+ * Query class for searching {@code RangeField} types by a defined {@link Relation}.
+ */
+abstract class RangeFieldQuery extends Query {
+ /** field name */
+ final String field;
+ /** query relation
+ * intersects: {@code CELL_CROSSES_QUERY},
+ * contains: {@code CELL_CONTAINS_QUERY},
+ * within: {@code CELL_WITHIN_QUERY} */
+ final QueryType queryType;
+ /** number of dimensions - max 4 */
+ final int numDims;
+ /** ranges encoded as a sortable byte array */
+ final byte[] ranges;
+ /** number of bytes per dimension */
+ final int bytesPerDim;
+
+ /** Used by {@code RangeFieldQuery} to check how each internal or leaf node relates to the query. */
+ enum QueryType {
+ /** Use this for intersects queries. */
+ INTERSECTS,
+ /** Use this for within queries. */
+ WITHIN,
+ /** Use this for contains */
+ CONTAINS,
+ /** Use this for crosses queries */
+ CROSSES
+ }
+
+ /**
+ * Create a query for searching indexed ranges that match the provided relation.
+ * @param field field name. must not be null.
+ * @param ranges encoded range values; this is done by the {@code RangeField} implementation
+ * @param queryType the query relation
+ */
+ RangeFieldQuery(String field, final byte[] ranges, final int numDims, final QueryType queryType) {
+ checkArgs(field, ranges, numDims);
+ if (queryType == null) {
+ throw new IllegalArgumentException("Query type cannot be null");
+ }
+ this.field = field;
+ this.queryType = queryType;
+ this.numDims = numDims;
+ this.ranges = ranges;
+ this.bytesPerDim = ranges.length / (2*numDims);
+ }
+
+ /** check input arguments */
+ private static void checkArgs(String field, final byte[] ranges, final int numDims) {
+ if (field == null) {
+ throw new IllegalArgumentException("field must not be null");
+ }
+ if (numDims > 4) {
+ throw new IllegalArgumentException("dimension size cannot be greater than 4");
+ }
+ if (ranges == null || ranges.length == 0) {
+ throw new IllegalArgumentException("encoded ranges cannot be null or empty");
+ }
+ }
+
+ /** Check indexed field info against the provided query data. */
+ private void checkFieldInfo(FieldInfo fieldInfo) {
+ if (fieldInfo.getPointDimensionCount()/2 != numDims) {
+ throw new IllegalArgumentException("field=\"" + field + "\" was indexed with numDims="
+ + fieldInfo.getPointDimensionCount()/2 + " but this query has numDims=" + numDims);
+ }
+ }
+
+ @Override
+ public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
+ return new ConstantScoreWeight(this, boost) {
+ final RangeFieldComparator target = new RangeFieldComparator();
+ private DocIdSet buildMatchingDocIdSet(LeafReader reader, PointValues values) throws IOException {
+ DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc(), values, field);
+ values.intersect(
+ new IntersectVisitor() {
+ DocIdSetBuilder.BulkAdder adder;
+ @Override
+ public void grow(int count) {
+ adder = result.grow(count);
+ }
+ @Override
+ public void visit(int docID) throws IOException {
+ adder.add(docID);
+ }
+ @Override
+ public void visit(int docID, byte[] leaf) throws IOException {
+ if (target.matches(leaf)) {
+ adder.add(docID);
+ }
+ }
+ @Override
+ public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
+ byte[] node = getInternalRange(minPackedValue, maxPackedValue);
+ // compute range relation for BKD traversal
+ if (target.intersects(node) == false) {
+ return Relation.CELL_OUTSIDE_QUERY;
+ } else if (target.within(node)) {
+ // target within cell; continue traversing:
+ return Relation.CELL_CROSSES_QUERY;
+ } else if (target.contains(node)) {
+ // target contains cell; add iff queryType is not a CONTAINS or CROSSES query:
+ return (queryType == QueryType.CONTAINS || queryType == QueryType.CROSSES) ?
+ Relation.CELL_OUTSIDE_QUERY : Relation.CELL_INSIDE_QUERY;
+ }
+ // target intersects cell; continue traversing:
+ return Relation.CELL_CROSSES_QUERY;
+ }
+ });
+ return result.build();
+ }
+
+ @Override
+ public Scorer scorer(LeafReaderContext context) throws IOException {
+ LeafReader reader = context.reader();
+ PointValues values = reader.getPointValues(field);
+ if (values == null) {
+ // no docs in this segment indexed any ranges
+ return null;
+ }
+ FieldInfo fieldInfo = reader.getFieldInfos().fieldInfo(field);
+ if (fieldInfo == null) {
+ // no docs in this segment indexed this field
+ return null;
+ }
+ checkFieldInfo(fieldInfo);
+ boolean allDocsMatch = true;
+ if (values.getDocCount() == reader.maxDoc()) {
+ // if query crosses, docs need to be further scrutinized
+ byte[] range = getInternalRange(values.getMinPackedValue(), values.getMaxPackedValue());
+ // if the internal node is not equal and not contained by the query, all docs do not match
+ if (queryType == QueryType.CROSSES || (!Arrays.equals(ranges, range)
+ && (target.contains(range) == false || queryType != QueryType.WITHIN))) {
+ allDocsMatch = false;
+ }
+ } else {
+ allDocsMatch = false;
+ }
+
+ DocIdSetIterator iterator = allDocsMatch == true ?
+ DocIdSetIterator.all(reader.maxDoc()) : buildMatchingDocIdSet(reader, values).iterator();
+ return new ConstantScoreScorer(this, score(), iterator);
+ }
+
+ /** get an encoded byte representation of the internal node; this is
+ * the lower half of the min array and the upper half of the max array */
+ private byte[] getInternalRange(byte[] min, byte[] max) {
+ byte[] range = new byte[min.length];
+ final int dimSize = numDims * bytesPerDim;
+ System.arraycopy(min, 0, range, 0, dimSize);
+ System.arraycopy(max, dimSize, range, dimSize, dimSize);
+ return range;
+ }
+ };
+ }
+
+ /**
+ * RangeFieldComparator class provides the core comparison logic for accepting or rejecting indexed
+ * {@code RangeField} types based on the defined query range and relation.
+ */
+ class RangeFieldComparator {
+ final Predicate<byte[]> predicate;
+
+ /** constructs the comparator based on the query type */
+ RangeFieldComparator() {
+ switch (queryType) {
+ case INTERSECTS:
+ predicate = this::intersects;
+ break;
+ case WITHIN:
+ predicate = this::contains;
+ break;
+ case CONTAINS:
+ predicate = this::within;
+ break;
+ case CROSSES:
+ // crosses first checks intersection (disjoint automatic fails),
+ // then ensures the query doesn't wholly contain the leaf:
+ predicate = (byte[] leaf) -> this.intersects(leaf)
+ && this.contains(leaf) == false;
+ break;
+ default:
+ throw new IllegalArgumentException("invalid queryType [" + queryType + "] found.");
+ }
+ }
+
+ /** determines if the candidate range matches the query request */
+ private boolean matches(final byte[] candidate) {
+ return (Arrays.equals(ranges, candidate) && queryType != QueryType.CROSSES)
+ || predicate.test(candidate);
+ }
+
+ /** check if query intersects candidate range */
+ private boolean intersects(final byte[] candidate) {
+ return relate((int d) -> compareMinMax(candidate, d) > 0 || compareMaxMin(candidate, d) < 0);
+ }
+
+ /** check if query is within candidate range */
+ private boolean within(final byte[] candidate) {
+ return relate((int d) -> compareMinMin(candidate, d) < 0 || compareMaxMax(candidate, d) > 0);
+ }
+
+ /** check if query contains candidate range */
+ private boolean contains(final byte[] candidate) {
+ return relate((int d) -> compareMinMin(candidate, d) > 0 || compareMaxMax(candidate, d) < 0);
+ }
+
+ /** internal method used by each relation method to test range relation logic */
+ private boolean relate(IntPredicate predicate) {
+ for (int d=0; d<numDims; ++d) {
+ if (predicate.test(d)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** compare the encoded min value (for the defined query dimension) with the encoded min value in the byte array */
+ private int compareMinMin(byte[] b, int dimension) {
+ // convert dimension to offset:
+ dimension *= bytesPerDim;
+ return StringHelper.compare(bytesPerDim, ranges, dimension, b, dimension);
+ }
+
+ /** compare the encoded min value (for the defined query dimension) with the encoded max value in the byte array */
+ private int compareMinMax(byte[] b, int dimension) {
+ // convert dimension to offset:
+ dimension *= bytesPerDim;
+ return StringHelper.compare(bytesPerDim, ranges, dimension, b, numDims * bytesPerDim + dimension);
+ }
+
+ /** compare the encoded max value (for the defined query dimension) with the encoded min value in the byte array */
+ private int compareMaxMin(byte[] b, int dimension) {
+ // convert dimension to offset:
+ dimension *= bytesPerDim;
+ return StringHelper.compare(bytesPerDim, ranges, numDims * bytesPerDim + dimension, b, dimension);
+ }
+
+ /** compare the encoded max value (for the defined query dimension) with the encoded max value in the byte array */
+ private int compareMaxMax(byte[] b, int dimension) {
+ // convert dimension to max offset:
+ dimension = numDims * bytesPerDim + dimension * bytesPerDim;
+ return StringHelper.compare(bytesPerDim, ranges, dimension, b, dimension);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = classHash();
+ hash = 31 * hash + field.hashCode();
+ hash = 31 * hash + numDims;
+ hash = 31 * hash + queryType.hashCode();
+ hash = 31 * hash + Arrays.hashCode(ranges);
+
+ return hash;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ return sameClassAs(o) &&
+ equalsTo(getClass().cast(o));
+ }
+
+ protected boolean equalsTo(RangeFieldQuery other) {
+ return Objects.equals(field, other.field) &&
+ numDims == other.numDims &&
+ Arrays.equals(ranges, other.ranges) &&
+ other.queryType == queryType;
+ }
+
+ @Override
+ public String toString(String field) {
+ StringBuilder sb = new StringBuilder();
+ if (this.field.equals(field) == false) {
+ sb.append(this.field);
+ sb.append(':');
+ }
+ sb.append("<ranges:");
+ sb.append(toString(ranges, 0));
+ for (int d=1; d<numDims; ++d) {
+ sb.append(' ');
+ sb.append(toString(ranges, d));
+ }
+ sb.append('>');
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string of a single value in a human-readable format for debugging.
+ * This is used by {@link #toString()}.
+ *
+ * @param dimension dimension of the particular value
+ * @param ranges encoded ranges, never null
+ * @return human readable value for debugging
+ */
+ protected abstract String toString(byte[] ranges, int dimension);
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/lucene/core/src/java/org/apache/lucene/index/PointValues.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/index/PointValues.java b/lucene/core/src/java/org/apache/lucene/index/PointValues.java
index dab9140..186dbd5 100644
--- a/lucene/core/src/java/org/apache/lucene/index/PointValues.java
+++ b/lucene/core/src/java/org/apache/lucene/index/PointValues.java
@@ -46,7 +46,7 @@ import org.apache.lucene.util.bkd.BKDWriter;
* <tr><td>{@code double}</td><td>{@link DoublePoint}</td></tr>
* <tr><td>{@code byte[]}</td><td>{@link BinaryPoint}</td></tr>
* <tr><td>{@link BigInteger}</td><td><a href="{@docRoot}/../sandbox/org/apache/lucene/document/BigIntegerPoint.html">BigIntegerPoint</a>*</td></tr>
- * <tr><td>{@link InetAddress}</td><td><a href="{@docRoot}/../sandbox/org/apache/lucene/document/InetAddressPoint.html">InetAddressPoint</a>*</td></tr>
+ * <tr><td>{@link InetAddress}</td><td><a href="{@docRoot}/../misc/org/apache/lucene/document/InetAddressPoint.html">InetAddressPoint</a>*</td></tr>
* </table>
* * in the <i>lucene-sandbox</i> jar<br>
* <p>