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>