You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by to...@apache.org on 2015/03/09 13:21:50 UTC

svn commit: r1665206 - in /jackrabbit/oak/branches/1.0: ./ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/ oak-core/src/te...

Author: tommaso
Date: Mon Mar  9 12:21:49 2015
New Revision: 1665206

URL: http://svn.apache.org/r1665206
Log:
OAK-2175 - backported to branch 1.0

Added:
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java
      - copied, changed from r1656019, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneRequestFacade.java
      - copied unchanged from r1656019, jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneRequestFacade.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/SpellcheckHelper.java
      - copied unchanged from r1656019, jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/SpellcheckHelper.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/SpellcheckTest.java
      - copied unchanged from r1656019, jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/SpellcheckTest.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/test/resources/org/apache/jackrabbit/oak/query/
      - copied from r1656019, jackrabbit/oak/trunk/oak-lucene/src/test/resources/org/apache/jackrabbit/oak/query/
    jackrabbit/oak/branches/1.0/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/jcr/query/SpellcheckTest.java
      - copied unchanged from r1656019, jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/jcr/query/SpellcheckTest.java
    jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/org/apache/jackrabbit/oak/query/sql1.txt
      - copied unchanged from r1656019, jackrabbit/oak/trunk/oak-solr-core/src/test/resources/org/apache/jackrabbit/oak/query/sql1.txt
Modified:
    jackrabbit/oak/branches/1.0/   (props changed)
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitor.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
    jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql1.txt
    jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt
    jackrabbit/oak/branches/1.0/oak-lucene/pom.xml
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
    jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java
    jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/FilterQueryParser.java
    jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
    jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/schema.xml
    jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml
    jackrabbit/oak/branches/1.0/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTestIT.java
    jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/schema.xml
    jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml

Propchange: jackrabbit/oak/branches/1.0/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Mar  9 12:21:49 2015
@@ -1,2 +1,2 @@
-/jackrabbit/oak/trunk:1584578,1584602,1584614,1584616,1584709,1584781,1584937,1585297,1585304-1585305,1585420,1585424,1585427,1585448,1585465,1585468,1585486,1585497,1585509,1585647,1585655-1585656,1585661,1585665-1585666,1585669-1585670,1585673,1585680,1585719,1585763,1585770,1585896,1585904,1585907,1585940,1585949,1585951,1585956,1585962-1585963,1586287,1586320,1586364,1586372,1586655,1586836,1587130,1587224,1587399,1587408,1587472,1587485,1587488,1587538,1587580,1587807,1588033,1588042,1588046,1588066,1588201,1589025,1589101,1589137,1589141,1589263,1589440,1589442,1589484,1589488,1589661,1589664,1589682,1589708,1589741,1589748,1589789,1589794,1589850,1589864,1590628,1590660,1590684,1590697,1590701,1590980,1590988,1591101,1591226,1591229,1591293,1591314,1591317,1591362,1591374,1591381,1591438,1591467,1591552,1591704,1591713,1591715,1591723,1591874,1592487,1592512,1592658,1592665,1592677,1592742,1592744,1592787,1592809,1592955,1593036,1593048,1593061,1593133,1593210-1593211,1593231
 ,1593245,1593250,1593294,1593304,1593317,1593342,1593554,1594158-1594164,1594166-1594167,1594169,1594237,1594800,1594808,1594835,1594888,1595147,1595457,1595856,1596241,1596474,1596534,1596844,1597569,1597795,1597854,1597860,1598292,1598302,1598352,1598369,1598595,1598631,1598696,1598732,1598797-1598798,1599299,1599332,1599416,1599434,1599671,1600088,1600935,1601309,1601388,1601578,1601649,1601676,1601757,1601768,1601814,1601833,1601838,1601853,1601878,1601888,1601922,1602156,1602170,1602174,1602179,1602183,1602201,1602207,1602227,1602256,1602261,1602342,1602796-1602797,1602800,1602809,1602853,1602872,1602914,1603155,1603307,1603401,1603441,1603748,1604166,1605030,1605036,1605038,1605292,1605447,1605526,1605670,1605725,1605831,1605852,1606077,1606079,1606087,1606638,1606641,1606644,1606708,1606711,1607031-1607032,1607077,1607127,1607141,1607152,1607185,1607196,1607331,1607362,1607366,1607392,1607526,1607557,1607664,1607737,1608560,1608731,1608783,1609064,1609081,1609165,1609214,1609
 488,1610489,1610592,1610603,1610634,1610658,1610664,1611021,1611041,1611270,1611275,1611277,1611313,1611332,1611584,1612560,1612825,1612993,1613018,1613041,1614265,1614272,1614344-1614345,1614384-1614385,1614397,1614405-1614406,1614574,1614591,1614593,1614596,1614604,1614689,1614807,1614835,1614891,1615417-1615418,1616182,1616236,1616463,1616719,1617417,1617451,1617463,1617711,1618158,1618613,1618624,1618709,1619222,1619411,1619695,1619800,1619808,1619815,1619823-1619824,1620512,1620581,1620585,1620634,1620898,1620905,1621115,1621123-1621124,1621168,1621192,1621201,1621706,1621962,1622197,1622201,1622207,1622250,1622479,1623364,1623766,1623827,1623949,1623969,1623973,1624216,1624317,1624551,1624559,1624973,1624993-1624994,1625025,1625036,1625158,1625224,1625237,1625299,1625348,1625620,1625916,1625962-1625963,1626021,1626053,1626163,1626168,1626175,1626191,1626265,1626770,1627047,1627052,1627228,1627346,1627470,1627473,1627479,1627503,1627586,1627590,1627715,1627731,1628180,1628198,1
 628262,1628447,1628608,1629688,1629840,1629917,1630055-1630057,1630156,1630299,1630338,1630773,1631283-1631284,1631333-1631334,1631617-1631619,1631630,1631699,1631704,1631711,1631967-1631969,1631986,1631990,1631999,1632002-1632003,1632017,1632258,1632264,1632270,1632293,1632303,1632592,1632605,1633315,1633559-1633560,1633562,1633567,1633571,1633598,1633608,1633641,1633687,1633697,1633768,1633783,1634505,1634513,1634774,1634779,1634781,1634792,1634803,1634814,1634816,1634838,1634841,1634852,1634864,1634896,1634898,1635044-1635045,1635060,1635077,1635089,1635102,1635108,1635218,1635387,1635435,1635518,1635563,1635586,1636336,1636348,1636505,1636585,1636799,1637368,1637382,1637413,1637651,1637815,1638779-1638783,1639260,1639577,1639622,1639963,1639966,1639973,1640134,1640143,1640555-1640556,1640694-1640695,1640715,1640722-1640723,1640728,1640863-1640872,1641340,1641350,1641352,1641541,1641596-1641599,1641601,1641662,1641671,1641695,1641771,1641802,1641811,1641950,1642031,1642056,164211
 9,1642285,1642648,1642667,1642954,1642959,1643111,1643178,1643186,1643204,1643287,1643767,1643774,1643982,1644016,1644106,1644366,1644383,1644397-1644398,1644407,1644479,1644547,1644552,1644554,1644588,1644645,1644650,1644654,1644689,1644750,1645421,1645424,1645459,1645585,1645611,1645637,1645646,1645660-1645663,1645888,1645901,1645948,1645966,1645970-1645971,1646014,1646164,1646174,1646469,1646684,1646766,1646795,1646981,1649743,1649803,1650015,1650239,1650529,1650797,1651323,1651382,1651643,1651652,1651730,1651988-1651989,1651996,1652024,1652035,1652058-1652059,1652075,1652127,1652158,1652467,1652965,1652971,1653207,1653446,1653463,1653484,1653572,1653579,1653591,1653804,1653809,1653813,1653848-1653850,1653882,1654116,1654174,1654743,1654756,1654778,1655049,1655054-1655055,1655086,1655237,1655248,1655996,1656027,1656394,1656400,1656425,1656427,1656453,1656628,1657804,1658470,1659483,1659527,1659550,1659578,1659765,1660154-1660155,1660383,1660409,1660426,1660676,1660870,1660872,166
 0897,1660903,1661069,1661122,1661146,1661158,1661226,1661630,1661643,1661645,1662313-1662315,1662323,1662450,1663241,1663275,1663288,1663448,1663565,1663666,1663705,1663730,1664038,1664184,1664228-1664229,1664231
+/jackrabbit/oak/trunk:1584578,1584602,1584614,1584616,1584709,1584781,1584937,1585297,1585304-1585305,1585420,1585424,1585427,1585448,1585465,1585468,1585486,1585497,1585509,1585647,1585655-1585656,1585661,1585665-1585666,1585669-1585670,1585673,1585680,1585719,1585763,1585770,1585896,1585904,1585907,1585940,1585949,1585951,1585956,1585962-1585963,1586287,1586320,1586364,1586372,1586655,1586836,1587130,1587224,1587399,1587408,1587472,1587485,1587488,1587538,1587580,1587807,1588033,1588042,1588046,1588066,1588201,1589025,1589101,1589137,1589141,1589263,1589440,1589442,1589484,1589488,1589661,1589664,1589682,1589708,1589741,1589748,1589789,1589794,1589850,1589864,1590628,1590660,1590684,1590697,1590701,1590980,1590988,1591101,1591226,1591229,1591293,1591314,1591317,1591362,1591374,1591381,1591438,1591467,1591552,1591704,1591713,1591715,1591723,1591874,1592487,1592512,1592658,1592665,1592677,1592742,1592744,1592787,1592809,1592955,1593036,1593048,1593061,1593133,1593210-1593211,1593231
 ,1593245,1593250,1593294,1593304,1593317,1593342,1593554,1594158-1594164,1594166-1594167,1594169,1594237,1594800,1594808,1594835,1594888,1595147,1595457,1595856,1596241,1596474,1596534,1596844,1597569,1597795,1597854,1597860,1598292,1598302,1598352,1598369,1598595,1598631,1598696,1598732,1598797-1598798,1599299,1599332,1599416,1599434,1599671,1600088,1600935,1601309,1601388,1601578,1601649,1601676,1601757,1601768,1601814,1601833,1601838,1601853,1601878,1601888,1601922,1602156,1602170,1602174,1602179,1602183,1602201,1602207,1602227,1602256,1602261,1602342,1602796-1602797,1602800,1602809,1602853,1602872,1602914,1603155,1603307,1603401,1603441,1603748,1604166,1605030,1605036,1605038,1605292,1605447,1605526,1605670,1605725,1605831,1605852,1606077,1606079,1606087,1606638,1606641,1606644,1606708,1606711,1607031-1607032,1607077,1607127,1607141,1607152,1607185,1607196,1607331,1607362,1607366,1607392,1607526,1607557,1607664,1607737,1608560,1608731,1608783,1609064,1609081,1609165,1609214,1609
 488,1610489,1610592,1610603,1610634,1610658,1610664,1611021,1611041,1611270,1611275,1611277,1611313,1611332,1611584,1612560,1612825,1612993,1613018,1613041,1614265,1614272,1614344-1614345,1614384-1614385,1614397,1614405-1614406,1614574,1614591,1614593,1614596,1614604,1614689,1614807,1614835,1614891,1615417-1615418,1616182,1616236,1616463,1616719,1617417,1617451,1617463,1617711,1618158,1618613,1618624,1618709,1619222,1619411,1619695,1619800,1619808,1619815,1619823-1619824,1620512,1620581,1620585,1620634,1620898,1620905,1621115,1621123-1621124,1621168,1621192,1621201,1621706,1621962,1622197,1622201,1622207,1622250,1622479,1623364,1623766,1623827,1623949,1623969,1623973,1624216,1624317,1624551,1624559,1624973,1624993-1624994,1625025,1625036,1625158,1625224,1625237,1625299,1625348,1625620,1625916,1625962-1625963,1626021,1626053,1626163,1626168,1626175,1626191,1626265,1626770,1627047,1627052,1627228,1627346,1627470,1627473,1627479,1627503,1627586,1627590,1627715,1627731,1628180,1628198,1
 628262,1628447,1628608,1629688,1629840,1629917,1630055-1630057,1630156,1630299,1630338,1630773,1631283-1631284,1631333-1631334,1631617-1631619,1631630,1631699,1631704,1631711,1631967-1631969,1631986,1631990,1631999,1632002-1632003,1632017,1632258,1632264,1632270,1632293,1632303,1632592,1632605,1633315,1633559-1633560,1633562,1633567,1633571,1633598,1633608,1633641,1633687,1633697,1633768,1633783,1634505,1634513,1634774,1634779,1634781,1634792,1634803,1634814,1634816,1634838,1634841,1634852,1634864,1634896,1634898,1635044-1635045,1635060,1635077,1635089,1635102,1635108,1635218,1635387,1635435,1635518,1635563,1635586,1636336,1636348,1636505,1636585,1636799,1637368,1637382,1637413,1637651,1637815,1638779-1638783,1639260,1639577,1639622,1639963,1639966,1639973,1640134,1640143,1640555-1640556,1640694-1640695,1640715,1640722-1640723,1640728,1640863-1640872,1641340,1641350,1641352,1641541,1641596-1641599,1641601,1641662,1641671,1641695,1641771,1641802,1641811,1641950,1642031,1642056,164211
 9,1642285,1642648,1642667,1642954,1642959,1643111,1643178,1643186,1643204,1643287,1643767,1643774,1643982,1644016,1644106,1644366,1644383,1644397-1644398,1644407,1644479,1644547,1644552,1644554,1644588,1644645,1644650,1644654,1644689,1644750,1645421,1645424,1645459,1645585,1645611,1645637,1645646,1645660-1645663,1645888,1645901,1645948,1645966,1645970-1645971,1646014,1646164,1646174,1646469,1646684,1646766,1646795,1646981,1649743,1649803,1650015,1650239,1650529,1650797,1651323,1651382,1651643,1651652,1651730,1651988-1651989,1651996,1652024,1652035,1652058-1652059,1652075,1652127,1652158,1652467,1652965,1652971,1653207,1653446,1653463,1653484,1653572,1653579,1653591,1653804,1653809,1653813,1653848-1653850,1653882,1654116,1654174,1654743,1654756,1654778,1655049,1655054-1655055,1655086,1655237,1655248,1655996,1656019,1656027,1656033,1656394,1656400,1656425,1656427,1656453,1656628,1656678,1657804,1658470,1659483,1659527,1659550,1659578,1659765,1660154-1660155,1660383,1660409,1660426,166
 0676,1660870,1660872,1660897,1660903,1661069,1661122,1661146,1661158,1661226,1661630,1661643,1661645,1662313-1662315,1662323,1662450,1663241,1663275,1663288,1663448,1663565,1663666,1663705,1663730,1664038,1664184,1664228-1664229,1664231
 /jackrabbit/trunk:1345480

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java Mon Mar  9 12:21:49 2015
@@ -62,6 +62,7 @@ import org.apache.jackrabbit.oak.query.a
 import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
 import org.apache.jackrabbit.oak.query.ast.SimilarImpl;
 import org.apache.jackrabbit.oak.query.ast.SourceImpl;
+import org.apache.jackrabbit.oak.query.ast.SpellcheckImpl;
 import org.apache.jackrabbit.oak.query.ast.UpperCaseImpl;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.query.index.TraversingIndex;
@@ -101,6 +102,11 @@ public class QueryImpl implements Query
      */
     public static final String REP_EXCERPT = "rep:excerpt";
 
+    /**
+     * The "rep:spellcheck" pseudo-property.
+     */
+    public static final String REP_SPELLCHECK = "rep:spellcheck()";
+
     private static final Logger LOG = LoggerFactory.getLogger(QueryImpl.class);
 
     SourceImpl source;
@@ -226,6 +232,13 @@ public class QueryImpl implements Query
                 node.setQuery(query);
                 node.bindSelector(source);
                 return super.visit(node);
+            }
+            
+            @Override
+            public boolean visit(SpellcheckImpl node) {
+                node.setQuery(query);
+                node.bindSelector(source);
+                return super.visit(node);
             }
 
             @Override

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java Mon Mar  9 12:21:49 2015
@@ -555,6 +555,15 @@ public class SQL2Parser {
             String language = readString().getValue(Type.STRING);
             read(",");
             c = factory.nativeFunction(selectorName, language, parseStaticOperand());
+        } else if ("SPELLCHECK".equalsIgnoreCase(functionName)) {
+            String selectorName;
+            if (currentTokenType == IDENTIFIER) {
+                selectorName = readName();
+                read(",");
+            } else {
+                selectorName = getOnlySelectorName();
+            }
+            c = factory.spellcheck(selectorName, parseStaticOperand());            
         } else {
             return null;
         }
@@ -827,26 +836,29 @@ public class SQL2Parser {
                         }
                         read(")");
                     }
+                    readOptionalAlias(column);
                 } else {                    
                     column.propertyName = readName();
-                    if (readIf(".")) {
+                    if (column.propertyName.equals("rep:spellcheck")) {
+                        if (readIf("(")) {
+                            read(")");
+                            column.propertyName = ":spellcheck";
+                        }
+                        readOptionalAlias(column);                        
+                    } else if (readIf(".")) {
                         column.selectorName = column.propertyName;
                         if (readIf("*")) {
                             column.propertyName = null;
                         } else {
                             column.propertyName = readName();
-                            if (readIf("AS")) {
-                                column.columnName = readName();
-                            } else {
+                            if (!readOptionalAlias(column)) {
                                 column.columnName =
                                         column.selectorName
                                         + "." + column.propertyName;
                             }
                         }
                     } else {
-                        if (readIf("AS")) {
-                            column.columnName = readName();
-                        }
+                        readOptionalAlias(column);
                     }
                 }
                 list.add(column);
@@ -854,6 +866,14 @@ public class SQL2Parser {
         }
         return list;
     }
+    
+    private boolean readOptionalAlias(ColumnOrWildcard column) throws ParseException {
+        if (readIf("AS")) {
+            column.columnName = readName();
+            return true;
+        }
+        return false;
+    }
 
     private ColumnImpl[] resolveColumns(ArrayList<ColumnOrWildcard> list) throws ParseException {
         ArrayList<ColumnImpl> columns = new ArrayList<ColumnImpl>();

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java Mon Mar  9 12:21:49 2015
@@ -157,4 +157,8 @@ public class AstElementFactory {
         return new SimilarImpl(selectorName, propertyName, path);
     }
 
+    public ConstraintImpl spellcheck(String selectorName, StaticOperandImpl expression) {
+        return new SpellcheckImpl(selectorName, expression);
+    }
+
 }

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitor.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitor.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitor.java Mon Mar  9 12:21:49 2015
@@ -79,8 +79,10 @@ public interface AstVisitor {
 
     boolean visit(UpperCaseImpl node);
 
-    boolean visit(NativeFunctionImpl nativeFunctionImpl);
+    boolean visit(NativeFunctionImpl node);
 
-    boolean visit(SimilarImpl similarImpl);
+    boolean visit(SimilarImpl node);
+    
+    boolean visit(SpellcheckImpl node);
 
 }
\ No newline at end of file

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java Mon Mar  9 12:21:49 2015
@@ -81,6 +81,15 @@ public abstract class AstVisitorBase imp
         node.getPathExpression().accept(this);
         return true;
     }
+    
+    /**
+     * Calls accept on the static operand in the spellcheck search constraint.
+     */
+    @Override
+    public boolean visit(SpellcheckImpl node) {
+        node.getExpression().accept(this);
+        return true;
+    }
 
     /**
      * Calls accept on the two sources and the join condition in the join node.

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Mon Mar  9 12:21:49 2015
@@ -620,6 +620,8 @@ public class SelectorImpl extends Source
             result = currentRow.getValue(QueryImpl.JCR_SCORE);
         } else if (oakPropertyName.equals(QueryImpl.REP_EXCERPT)) {
             result = currentRow.getValue(QueryImpl.REP_EXCERPT);
+        } else if (oakPropertyName.equals(QueryImpl.REP_SPELLCHECK)) {
+            result = currentRow.getValue(QueryImpl.REP_SPELLCHECK);
         } else {
             result = PropertyValues.create(t.getProperty(oakPropertyName));
         }

Copied: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java (from r1656019, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java?p2=jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java&r1=1656019&r2=1665206&rev=1665206&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java Mon Mar  9 12:21:49 2015
@@ -19,6 +19,7 @@
 package org.apache.jackrabbit.oak.query.ast;
 
 import java.util.Collections;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
@@ -28,7 +29,7 @@ import org.apache.jackrabbit.oak.spi.que
 import org.apache.jackrabbit.oak.spi.query.QueryIndex.FulltextQueryIndex;
 
 /**
- * Support for "similar(...)
+ * Support for "spellcheck(...)
  */
 public class SpellcheckImpl extends ConstraintImpl {
     
@@ -74,6 +75,11 @@ public class SpellcheckImpl extends Cons
     }
 
     @Override
+    public Map<DynamicOperandImpl, Set<StaticOperandImpl>> getInMap() {
+        return Collections.emptyMap();
+    }
+
+    @Override
     public void restrict(FilterImpl f) {
         if (f.getSelector().equals(selector)) {
             PropertyValue p = expression.currentValue();

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java Mon Mar  9 12:21:49 2015
@@ -544,7 +544,38 @@ abstract class Expression {
             return false;
         }
     
-    } 
+    }
+
+    /**
+     * A rep:spellcheck condition.
+     */
+    static class Spellcheck extends Expression {
+
+        final Expression term;
+
+        Spellcheck(Expression term) {
+            this.term = term;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder buff = new StringBuilder("spellcheck(");
+            buff.append(term);
+            buff.append(')');
+            return buff.toString();
+        }
+
+        @Override
+        boolean isCondition() {
+            return true;
+        }
+
+        @Override
+        boolean isName() {
+            return false;
+        }
+
+    }
 
     /**
      * A function call.

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java Mon Mar  9 12:21:49 2015
@@ -209,6 +209,12 @@ public class XPathToSQL2Converter {
                         readExcerpt();
                         Expression.Property p = new Expression.Property(currentSelector, "rep:excerpt", false);
                         statement.addSelectColumn(p);
+                    } else if (readIf("rep:spellcheck")) {
+                        // only rep:spellcheck() is currently supported
+                        read("(");
+                        read(")");                        
+                        Expression.Property p = new Expression.Property(currentSelector, "rep:spellcheck()", false);
+                        statement.addSelectColumn(p);
                     }
                 } while (readIf("|"));
                 read(")");
@@ -622,12 +628,12 @@ public class XPathToSQL2Converter {
             Expression.Similar f = new Expression.Similar(property, path);
             return f;
         } else if ("rep:spellcheck".equals(functionName)) {
-            // TODO maybe support rep:spellcheck as in
-            // /jcr:root[rep:spellcheck('${query}')]/(rep:spellcheck())            
-            throw getSyntaxError("rep:spellcheck is not supported");
+            Expression term = parseExpression();
+            read(")");
+            return new Expression.Spellcheck(term);
         } else {
             throw getSyntaxError("jcr:like | jcr:contains | jcr:score | xs:dateTime | " + 
-                    "fn:lower-case | fn:upper-case | fn:name");
+                    "fn:lower-case | fn:upper-case | fn:name | rep:similar | rep:spellcheck");
         }
     }
 

Modified: jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql1.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql1.txt?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql1.txt (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql1.txt Mon Mar  9 12:21:49 2015
@@ -26,6 +26,12 @@
 
 # sql-1 query (nt:unstructured needs to be escaped in sql-2)
 
+sql1 SELECT [rep:spellcheck()] FROM nt:base WHERE [jcr:path] = '/' AND SPELLCHECK('jackrabit')
+java.lang.IllegalArgumentException: No full-text index was found that can process the condition spellcheck([nt:base], 'jackrabit')
+
+sql1 SELECT rep:spellcheck() FROM nt:base WHERE jcr:path = '/' AND SPELLCHECK('jackrabit') 
+java.lang.IllegalArgumentException: No full-text index was found that can process the condition spellcheck([nt:base], 'jackrabit')
+
 sql1 select prop1 from nt:unstructured where prop1 is not null order by prop1 asc
 
 sql1 select excerpt(.) from nt:resource where contains(., 'jackrabbit')

Modified: jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt Mon Mar  9 12:21:49 2015
@@ -1353,7 +1353,7 @@ xpath2sql //element(*, my:type)[@my:valu
 invalid: Query: //element(*, my:type)[@my:value = [(*)'x']; expected: @, true, false, -, +, *, ., @, (
 
 xpath2sql //element(*, my:type)[jcr:strike(@title,'%Java%')]
-invalid: Query: //element(*, my:type)[jcr:strike(@(*)title,'%Java%')]; expected: jcr:like | jcr:contains | jcr:score | xs:dateTime | fn:lower-case | fn:upper-case | fn:name
+invalid: Query: //element(*, my:type)[jcr:strike(@(*)title,'%Java%')]; expected: jcr:like | jcr:contains | jcr:score | xs:dateTime | fn:lower-case | fn:upper-case | fn:name | rep:similar | rep:spellcheck
 
 xpath2sql //element(*, my:type)[
 invalid: Query: //element(*, my:type)(*)[; expected: fn:not, not, (, @, true, false, -, +, *, ., @, (

Modified: jackrabbit/oak/branches/1.0/oak-lucene/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/pom.xml?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/pom.xml (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/pom.xml Mon Mar  9 12:21:49 2015
@@ -198,6 +198,12 @@
       <version>${lucene.version}</version>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-suggest</artifactId>
+      <version>${lucene.version}</version>
+      <scope>provided</scope>
+    </dependency>
 
     <!-- Logging -->
     <dependency>

Modified: jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java Mon Mar  9 12:21:49 2015
@@ -58,6 +58,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
 import org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.IndexingRule;
 import org.apache.jackrabbit.oak.plugins.index.lucene.util.MoreLikeThisHelper;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.SpellcheckHelper;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.query.QueryImpl;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextAnd;
@@ -99,6 +100,7 @@ import org.apache.lucene.search.TermQuer
 import org.apache.lucene.search.TermRangeQuery;
 import org.apache.lucene.search.TopDocs;
 import org.apache.lucene.search.WildcardQuery;
+import org.apache.lucene.search.spell.SuggestWord;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.automaton.Automaton;
 import org.apache.lucene.util.automaton.CompiledAutomaton;
@@ -242,7 +244,7 @@ public class LuceneIndex implements Adva
             // we only restrict non-full-text conditions if there is
             // no relative property in the full-text constraint
             boolean nonFullTextConstraints = parent.isEmpty();
-            String planDesc = getQuery(filter, null, nonFullTextConstraints, index.getDefinition()) + " ft:(" + ft + ")";
+            String planDesc = getLuceneRequest(filter, null, nonFullTextConstraints, index.getDefinition()) + " ft:(" + ft + ")";
             if (!parent.isEmpty()) {
                 planDesc += " parent:" + parent;
             }
@@ -277,6 +279,7 @@ public class LuceneIndex implements Adva
             private final Set<String> seenPaths = Sets.newHashSet();
             private ScoreDoc lastDoc;
             private int nextBatchSize = LUCENE_QUERY_BATCH_SIZE;
+            private boolean noDocs = false;
 
             @Override
             protected LuceneResultRow computeNext() {
@@ -321,33 +324,49 @@ public class LuceneIndex implements Adva
              * @return true if any document is loaded
              */
             private boolean loadDocs() {
+
+                if (noDocs) {
+                    return false;
+                }
+
                 ScoreDoc lastDocToRecord = null;
 
                 IndexNode indexNode = tracker.acquireIndexNode((String) plan.getAttribute(ATTR_INDEX_PATH));
                 checkState(indexNode != null);
                 try {
                     IndexSearcher searcher = indexNode.getSearcher();
-                    Query query = getQuery(filter, searcher.getIndexReader(),
+                    LuceneRequestFacade luceneRequestFacade = getLuceneRequest(filter, searcher.getIndexReader(),
                             nonFullTextConstraints, indexNode.getDefinition());
-                    TopDocs docs;
-                    long time = System.currentTimeMillis();
-                    if (lastDoc != null) {
-                        LOG.debug("loading the next {} entries for query {}", nextBatchSize, query);
-                        docs = searcher.searchAfter(lastDoc, query, nextBatchSize);
-                    } else {
-                        LOG.debug("loading the first {} entries for query {}", nextBatchSize, query);
-                        docs = searcher.search(query, nextBatchSize);
-                    }
-                    time = System.currentTimeMillis() - time;
-                    LOG.debug("... took {} ms", time);
-                    nextBatchSize = (int) Math.min(nextBatchSize * 2L, 100000);
-
-                    for (ScoreDoc doc : docs.scoreDocs) {
-                        LuceneResultRow row = convertToRow(doc, searcher);
-                        if(row != null) {
-                            queue.add(row);
+                    if (luceneRequestFacade.getLuceneRequest() instanceof Query) {
+                        Query query = (Query) luceneRequestFacade.getLuceneRequest();
+                        TopDocs docs;
+                        long time = System.currentTimeMillis();
+                        if (lastDoc != null) {
+                            LOG.debug("loading the next {} entries for query {}", nextBatchSize, query);
+                            docs = searcher.searchAfter(lastDoc, query, nextBatchSize);
+                        } else {
+                            LOG.debug("loading the first {} entries for query {}", nextBatchSize, query);
+                            docs = searcher.search(query, nextBatchSize);
                         }
-                        lastDocToRecord = doc;
+                        time = System.currentTimeMillis() - time;
+                        LOG.debug("... took {} ms", time);
+                        nextBatchSize = (int) Math.min(nextBatchSize * 2L, 100000);
+
+                        for (ScoreDoc doc : docs.scoreDocs) {
+                            LuceneResultRow row = convertToRow(doc, searcher);
+                            if (row != null) {
+                                queue.add(row);
+                            }
+                            lastDocToRecord = doc;
+                        }
+                    } else if (luceneRequestFacade.getLuceneRequest() instanceof SuggestWord[]) {
+                        SuggestWord[] intent = (SuggestWord[]) luceneRequestFacade.getLuceneRequest();
+                        Collection<String> suggestedWords = new ArrayList<String>(intent.length);
+                        for (SuggestWord suggestWord : intent) {
+                            suggestedWords.add(suggestWord.string);
+                        }
+                        queue.add(new LuceneResultRow(suggestedWords));
+                        noDocs = true;
                     }
                 } catch (IOException e) {
                     LOG.warn("query via {} failed.", LuceneIndex.this, e);
@@ -430,12 +449,11 @@ public class LuceneIndex implements Adva
      * @param nonFullTextConstraints whether non-full-text constraints (such a
      *            path, node type, and so on) should be added to the Lucene
      *            query
-     * @param analyzer the Lucene analyzer used for building the fulltext query
      * @param indexDefinition nodestate that contains the index definition
      * @return the Lucene query
      */
-    private static Query getQuery(Filter filter, IndexReader reader,
-            boolean nonFullTextConstraints, IndexDefinition indexDefinition) {
+    private static LuceneRequestFacade getLuceneRequest(Filter filter, IndexReader reader,
+                                                        boolean nonFullTextConstraints, IndexDefinition indexDefinition) {
         List<Query> qs = new ArrayList<Query>();
         Analyzer analyzer = indexDefinition.getAnalyzer();
         FullTextExpression ft = filter.getFullTextConstraint();
@@ -459,6 +477,12 @@ public class LuceneIndex implements Adva
                     }
                 }
             }
+            if (query.startsWith("spellcheck?")) {
+                String spellcheckQueryString = query.replace("spellcheck?", "");
+                if (reader != null) {
+                    return new LuceneRequestFacade<SuggestWord[]>(SpellcheckHelper.getSpellcheck(spellcheckQueryString, reader));
+                }
+            }
             else {
                 try {
                     qs.add(queryParser.parse(query));
@@ -471,16 +495,16 @@ public class LuceneIndex implements Adva
                     indexDefinition);
         }
         if (qs.size() == 0) {
-            return new MatchAllDocsQuery();
+            return new LuceneRequestFacade<Query>(new MatchAllDocsQuery());
         }
         if (qs.size() == 1) {
-            return qs.get(0);
+            return new LuceneRequestFacade<Query>(qs.get(0));
         }
         BooleanQuery bq = new BooleanQuery();
         for (Query q : qs) {
             bq.add(q, MUST);
         }
-        return bq;
+        return new LuceneRequestFacade<Query>(bq);
     }
 
     private static void addNonFullTextConstraints(List<Query> qs,
@@ -739,19 +763,22 @@ public class LuceneIndex implements Adva
 
             @Override
             public boolean visit(FullTextTerm term) {
-                String p = term.getPropertyName();
+                return visitTerm(term.getPropertyName(), term.getText(), term.getBoost(), term.isNot());
+            }
+
+            private boolean visitTerm(String propertyName, String text, String boost, boolean not) {
+                String p = propertyName;
                 if (p != null && p.indexOf('/') >= 0) {
                     p = getName(p);
                 }
-                Query q = tokenToQuery(term.getText(), p, analyzer, reader);
+                Query q = tokenToQuery(text, p, analyzer, reader);
                 if (q == null) {
                     return false;
                 }
-                String boost = term.getBoost();
                 if (boost != null) {
                     q.setBoost(Float.parseFloat(boost));
                 }
-                if (term.isNot()) {
+                if (not) {
                     BooleanQuery bq = new BooleanQuery();
                     bq.add(q, MUST_NOT);
                     result.set(bq);
@@ -938,10 +965,18 @@ public class LuceneIndex implements Adva
     static class LuceneResultRow {
         final String path;
         final double score;
+        final Iterable<String> suggestWords;
 
         LuceneResultRow(String path, double score) {
             this.path = path;
             this.score = score;
+            this.suggestWords = Collections.emptySet();
+        }
+
+        LuceneResultRow(Iterable<String> suggestWords) {
+            this.path = "/";
+            this.score = 1.0d;
+            this.suggestWords = suggestWords;
         }
 
         @Override
@@ -949,16 +984,16 @@ public class LuceneIndex implements Adva
             return String.format("%s (%1.2f)", path, score);
         }
     }
-    
+
     /**
      * A cursor over Lucene results. The result includes the path,
      * and the jcr:score pseudo-property as returned by Lucene.
      */
     static class LucenePathCursor implements Cursor {
-        
+
         private final Cursor pathCursor;
         LuceneResultRow currentRow;
-        
+
         LucenePathCursor(final Iterator<LuceneResultRow> it, QueryEngineSettings settings) {
             Iterator<String> pathIterator = new Iterator<String>() {
 
@@ -969,7 +1004,7 @@ public class LuceneIndex implements Adva
 
                 @Override
                 public String next() {
-                    currentRow = it.next(); 
+                    currentRow = it.next();
                     return currentRow.path;
                 }
 
@@ -977,11 +1012,11 @@ public class LuceneIndex implements Adva
                 public void remove() {
                     it.remove();
                 }
-                
+
             };
             pathCursor = new PathCursor(pathIterator, true, settings);
         }
-        
+
 
         @Override
         public boolean hasNext() {
@@ -1009,9 +1044,12 @@ public class LuceneIndex implements Adva
                     if (QueryImpl.JCR_SCORE.equals(columnName)) {
                         return PropertyValues.newDouble(currentRow.score);
                     }
+                    if (QueryImpl.REP_SPELLCHECK.equals(columnName)) {
+                        return PropertyValues.newString(currentRow.suggestWords);
+                    }
                     return pathRow.getValue(columnName);
                 }
-                
+
             };
         }
     }

Modified: jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java Mon Mar  9 12:21:49 2015
@@ -21,7 +21,9 @@ package org.apache.jackrabbit.oak.plugin
 import java.io.IOException;
 import java.io.StringReader;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.List;
@@ -42,6 +44,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.IndexingRule;
 import org.apache.jackrabbit.oak.plugins.index.lucene.IndexPlanner.PlanResult;
 import org.apache.jackrabbit.oak.plugins.index.lucene.util.MoreLikeThisHelper;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.SpellcheckHelper;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.query.QueryImpl;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextAnd;
@@ -87,6 +90,7 @@ import org.apache.lucene.search.TermQuer
 import org.apache.lucene.search.TermRangeQuery;
 import org.apache.lucene.search.TopDocs;
 import org.apache.lucene.search.WildcardQuery;
+import org.apache.lucene.search.spell.SuggestWord;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.automaton.Automaton;
 import org.apache.lucene.util.automaton.CompiledAutomaton;
@@ -224,7 +228,7 @@ public class LucenePropertyIndex impleme
                     .append("(")
                     .append(path)
                     .append(") ");
-            sb.append(getQuery(plan, null));
+            sb.append(getLuceneRequest(plan, null));
             if(plan.getSortOrder() != null && !plan.getSortOrder().isEmpty()){
                 sb.append(" ordering:").append(plan.getSortOrder());
             }
@@ -253,6 +257,7 @@ public class LucenePropertyIndex impleme
             private final Set<String> seenPaths = Sets.newHashSet();
             private ScoreDoc lastDoc;
             private int nextBatchSize = LUCENE_QUERY_BATCH_SIZE;
+            private boolean noDocs = false;
 
             @Override
             protected LuceneResultRow computeNext() {
@@ -292,40 +297,56 @@ public class LucenePropertyIndex impleme
              * @return true if any document is loaded
              */
             private boolean loadDocs() {
+
+                if (noDocs) {
+                    return false;
+                }
+
                 ScoreDoc lastDocToRecord = null;
 
                 IndexNode indexNode = acquireIndexNode(plan);
                 checkState(indexNode != null);
                 try {
                     IndexSearcher searcher = indexNode.getSearcher();
-                    Query query = getQuery(plan, searcher.getIndexReader());
-                    TopDocs docs;
-                    long time = System.currentTimeMillis();
-                    if (lastDoc != null) {
-                        LOG.debug("loading the next {} entries for query {}", nextBatchSize, query);
-                        if (sort == null) {
-                            docs = searcher.searchAfter(lastDoc, query, nextBatchSize);
+                    LuceneRequestFacade luceneRequestFacade = getLuceneRequest(plan, searcher.getIndexReader());
+                    if (luceneRequestFacade.getLuceneRequest() instanceof Query) {
+                        Query query = (Query) luceneRequestFacade.getLuceneRequest();
+                        TopDocs docs;
+                        long time = System.currentTimeMillis();
+                        if (lastDoc != null) {
+                            LOG.debug("loading the next {} entries for query {}", nextBatchSize, query);
+                            if (sort == null) {
+                                docs = searcher.searchAfter(lastDoc, query, nextBatchSize);
+                            } else {
+                                docs = searcher.searchAfter(lastDoc, query, LUCENE_QUERY_BATCH_SIZE, sort);
+                            }
                         } else {
-                            docs = searcher.searchAfter(lastDoc, query, LUCENE_QUERY_BATCH_SIZE, sort);
+                            LOG.debug("loading the first {} entries for query {}", nextBatchSize, query);
+                            if (sort == null) {
+                                docs = searcher.search(query, nextBatchSize);
+                            } else {
+                                docs = searcher.search(query, LUCENE_QUERY_BATCH_SIZE, sort);
+                            }
                         }
-                    } else {
-                        LOG.debug("loading the first {} entries for query {}", nextBatchSize, query);
-                        if (sort == null) {
-                            docs = searcher.search(query, nextBatchSize);
-                        } else {
-                            docs = searcher.search(query, LUCENE_QUERY_BATCH_SIZE, sort);
+                        time = System.currentTimeMillis() - time;
+                        LOG.debug("... took {} ms", time);
+                        nextBatchSize = (int) Math.min(nextBatchSize * 2L, 100000);
+
+                        for (ScoreDoc doc : docs.scoreDocs) {
+                            LuceneResultRow row = convertToRow(doc, searcher);
+                            if (row != null) {
+                                queue.add(row);
+                            }
+                            lastDocToRecord = doc;
                         }
-                    }
-                    time = System.currentTimeMillis() - time;
-                    LOG.debug("... took {} ms", time);
-                    nextBatchSize = (int) Math.min(nextBatchSize * 2L, 100000);
-
-                    for (ScoreDoc doc : docs.scoreDocs) {
-                        LuceneResultRow row = convertToRow(doc, searcher);
-                        if(row != null) {
-                            queue.add(row);
+                    } else if (luceneRequestFacade.getLuceneRequest() instanceof SuggestWord[]) {
+                        SuggestWord[] suggestWords = (SuggestWord[]) luceneRequestFacade.getLuceneRequest();
+                        String[] suggestedWordsStrings = new String[suggestWords.length];
+                        for (int i = 0; i < suggestWords.length; i++) {
+                            suggestedWordsStrings[i] = suggestWords[i].string;
                         }
-                        lastDocToRecord = doc;
+                        queue.add(new LuceneResultRow(suggestedWordsStrings));
+                        noDocs = true;
                     }
                 } catch (IOException e) {
                     LOG.warn("query via {} failed.", LucenePropertyIndex.this, e);
@@ -426,14 +447,9 @@ public class LucenePropertyIndex impleme
      *
      * @param plan index plan containing filter details
      * @param reader the Lucene reader
-     * @param nonFullTextConstraints whether non-full-text constraints (such a
-     *            path, node type, and so on) should be added to the Lucene
-     *            query
-     * @param analyzer the Lucene analyzer used for building the fulltext query
-     * @param defn nodestate that contains the index definition
      * @return the Lucene query
      */
-    private static Query getQuery(IndexPlan plan, IndexReader reader) {
+    private static LuceneRequestFacade getLuceneRequest(IndexPlan plan, IndexReader reader) {
         List<Query> qs = new ArrayList<Query>();
         Filter filter = plan.getFilter();
         FullTextExpression ft = filter.getFullTextConstraint();
@@ -466,6 +482,11 @@ public class LucenePropertyIndex impleme
                         qs.add(moreLikeThis);
                     }
                 }
+            } else if (query.startsWith("spellcheck?")) {
+                String spellcheckQueryString = query.replace("spellcheck?", "");
+                if (reader != null) {
+                    return new LuceneRequestFacade<SuggestWord[]>(SpellcheckHelper.getSpellcheck(spellcheckQueryString, reader));
+                }
             }
             else {
                 try {
@@ -503,24 +524,18 @@ public class LucenePropertyIndex impleme
                 //When called in planning mode then some queries like rep:similar
                 //cannot create query as reader is not provided. In such case we
                 //just return match all queries
-                return new MatchAllDocsQuery();
-            }
-            //For purely nodeType based queries all the documents would have to
-            //be returned (if the index definition has a single rule)
-            if (planResult.evaluateNodeTypeRestriction()) {
-                return new MatchAllDocsQuery();
+                return new LuceneRequestFacade<Query>(new MatchAllDocsQuery());
             }
-
-            throw new IllegalStateException("No query created for filter " + filter);
+            return new LuceneRequestFacade<Query>(new MatchAllDocsQuery());
         }
         if (qs.size() == 1) {
-            return qs.get(0);
+            return new LuceneRequestFacade<Query>(qs.get(0));
         }
         BooleanQuery bq = new BooleanQuery();
         for (Query q : qs) {
             bq.add(q, MUST);
         }
-        return bq;
+        return new LuceneRequestFacade<Query>(bq);
     }
 
     private static void addNonFullTextConstraints(List<Query> qs,
@@ -1107,10 +1122,18 @@ public class LucenePropertyIndex impleme
     static class LuceneResultRow {
         final String path;
         final double score;
+        final String[] suggestWords;
 
         LuceneResultRow(String path, double score) {
             this.path = path;
             this.score = score;
+            this.suggestWords = new String[0];
+        }
+
+        LuceneResultRow(String[] suggestWords) {
+            this.path = "/";
+            this.score = 1.0d;
+            this.suggestWords = suggestWords;
         }
 
         @Override
@@ -1185,6 +1208,9 @@ public class LucenePropertyIndex impleme
                     if (QueryImpl.JCR_SCORE.equals(columnName)) {
                         return PropertyValues.newDouble(currentRow.score);
                     }
+                    if (QueryImpl.REP_SPELLCHECK.equals(columnName)) {
+                        return PropertyValues.newString(Arrays.toString(currentRow.suggestWords));
+                    }
                     return pathRow.getValue(columnName);
                 }
                 

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java Mon Mar  9 12:21:49 2015
@@ -101,7 +101,7 @@ public class AdvancedSolrQueryIndex exte
     }
 
     @Override
-    void onRetrievedResults(Filter filter, SolrDocumentList docs) {
+    void onRetrievedDocs(Filter filter, SolrDocumentList docs) {
         // update estimates cache
         cache.put(filter.toString(), docs.getNumFound());
     }

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/FilterQueryParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/FilterQueryParser.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/FilterQueryParser.java (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/FilterQueryParser.java Mon Mar  9 12:21:49 2015
@@ -78,26 +78,38 @@ class FilterQueryParser {
                             if (kv.length != 2) {
                                 throw new RuntimeException("Unparsable native HTTP Solr query");
                             } else {
-                                if ("stream.body".equals(kv[0])) {
-                                    kv[0] = "q";
-                                    String mltFlString = "mlt.fl=";
-                                    int mltFlIndex = parameterString.indexOf(mltFlString);
-                                    if (mltFlIndex > -1) {
-                                        int beginIndex = mltFlIndex + mltFlString.length();
-                                        int endIndex = parameterString.indexOf('&', beginIndex);
-                                        String fields;
-                                        if (endIndex > beginIndex) {
-                                            fields = parameterString.substring(beginIndex, endIndex);
-                                        } else {
-                                            fields = parameterString.substring(beginIndex);
+                                // more like this
+                                if ("/mlt".equals(requestHandlerString)) {
+                                    if ("stream.body".equals(kv[0])) {
+                                        kv[0] = "q";
+                                        String mltFlString = "mlt.fl=";
+                                        int mltFlIndex = parameterString.indexOf(mltFlString);
+                                        if (mltFlIndex > -1) {
+                                            int beginIndex = mltFlIndex + mltFlString.length();
+                                            int endIndex = parameterString.indexOf('&', beginIndex);
+                                            String fields;
+                                            if (endIndex > beginIndex) {
+                                                fields = parameterString.substring(beginIndex, endIndex);
+                                            } else {
+                                                fields = parameterString.substring(beginIndex);
+                                            }
+                                            kv[1] = "_query_:\"{!dismax qf=" + fields + " q.op=OR}" + kv[1] + "\"";
                                         }
-                                        kv[1] = "_query_:\"{!dismax qf=" + fields + " q.op=OR}" + kv[1] + "\"";
+                                    }
+                                    if ("mlt.fl".equals(kv[0]) && ":path".equals(kv[1])) {
+                                        // rep:similar passes the path of the node to find similar documents for in the :path
+                                        // but needs its indexed content to find similar documents
+                                        kv[1] = configuration.getCatchAllField();
                                     }
                                 }
-                                if ("mlt.fl".equals(kv[0]) && ":path".equals(kv[1])) {
-                                    // rep:similar passes the path of the node to find similar documents for in the :path
-                                    // but needs its indexed content to find similar documents
-                                    kv[1] = configuration.getCatchAllField();
+                                if ("/spellcheck".equals(requestHandlerString)) {
+                                    if ("term".equals(kv[0])) {
+                                        kv[0] = "spellcheck.q";
+                                    }
+                                    solrQuery.setParam("spellcheck", true);
+
+                                    // TODO : this should not be always passed to avoid building the dictionary on each spellcheck request
+                                    solrQuery.setParam("spellcheck.build", true);
                                 }
                                 solrQuery.setParam(kv[0], kv[1]);
                             }
@@ -285,7 +297,7 @@ class FilterQueryParser {
 
     private static boolean isSupportedHttpRequest(String nativeQueryString) {
         // the query string starts with ${supported-handler.selector}?
-        return nativeQueryString.matches("(mlt|query|select|get)\\\\?.*");
+        return nativeQueryString.matches("(spellcheck|mlt|query|select|get)\\\\?.*");
     }
 
     private static void setDefaults(SolrQuery solrQuery, OakSolrConfiguration configuration) {

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java Mon Mar  9 12:21:49 2015
@@ -47,6 +47,8 @@ import org.apache.jackrabbit.oak.spi.que
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.SpellCheckResponse;
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrDocumentList;
 import org.slf4j.Logger;
@@ -193,15 +195,17 @@ public class SolrQueryIndex implements F
             final int parentDepth = getDepth(parent);
 
             cursor = new SolrRowCursor(new AbstractIterator<SolrResultRow>() {
+
                 private final Set<String> seenPaths = Sets.newHashSet();
                 private final Deque<SolrResultRow> queue = Queues.newArrayDeque();
                 private SolrDocument lastDoc;
                 private int offset = 0;
+                private boolean noDocs = false;
                 public long numFound = 0;
 
                 @Override
                 protected SolrResultRow computeNext() {
-                    while (!queue.isEmpty() || loadDocs()) {
+                    if (!queue.isEmpty() || loadDocs()) {
                         return queue.remove();
                     }
                     return endOfData();
@@ -238,6 +242,12 @@ public class SolrQueryIndex implements F
                  */
                 private boolean loadDocs() {
 
+                    if (noDocs) {
+                        return false;
+                    }
+
+                    SolrDocument lastDocToRecord = null;
+
                     try {
                         if (log.isDebugEnabled()) {
                             log.debug("converting filter {}", filter);
@@ -254,9 +264,11 @@ public class SolrQueryIndex implements F
                         if (log.isDebugEnabled()) {
                             log.debug("sending query {}", query);
                         }
-                        SolrDocumentList docs = solrServer.query(query).getResults();
+                        QueryResponse queryResponse = solrServer.query(query);
+
+                        SolrDocumentList docs = queryResponse.getResults();
 
-                        onRetrievedResults(filter, docs);
+                        onRetrievedDocs(filter, docs);
 
                         if (log.isDebugEnabled()) {
                             log.debug("getting docs {}", docs);
@@ -273,6 +285,19 @@ public class SolrQueryIndex implements F
                                 }
                             }
                         }
+
+                        // handle spellcheck
+                        SpellCheckResponse spellCheckResponse = queryResponse.getSpellCheckResponse();
+                        if (spellCheckResponse != null && spellCheckResponse.getSuggestions() != null &&
+                                spellCheckResponse.getSuggestions().size() > 0) {
+                            SolrDocument fakeDoc = new SolrDocument();
+                            for (SpellCheckResponse.Suggestion suggestion : spellCheckResponse.getSuggestions()) {
+                                fakeDoc.addField("rep:spellcheck()", suggestion.getAlternatives());
+                            }
+                            queue.add(new SolrResultRow("/", 1.0, fakeDoc));
+                            noDocs = true;
+                        }
+
                     } catch (Exception e) {
                         if (log.isWarnEnabled()) {
                             log.warn("query via {} failed.", solrServer, e);
@@ -289,7 +314,7 @@ public class SolrQueryIndex implements F
         return cursor;
     }
 
-    void onRetrievedResults(Filter filter, SolrDocumentList docs) {
+    void onRetrievedDocs(Filter filter, SolrDocumentList docs) {
         // do nothing
     }
 
@@ -308,11 +333,12 @@ public class SolrQueryIndex implements F
     }
 
     static boolean isIgnoredProperty(String propertyName, OakSolrConfiguration configuration) {
-        return !configuration.useForPropertyRestrictions() // Solr index not used for properties
-                || (configuration.getUsedProperties().size() > 0 && !configuration.getUsedProperties().contains(propertyName)) // not explicitly contained in the used properties
-                || propertyName.contains("/") // no child-level property restrictions
-                || "rep:excerpt".equals(propertyName) // rep:excerpt is handled by the query engine
-                || configuration.getIgnoredProperties().contains(propertyName); // property is explicitly ignored
+        return !(NATIVE_LUCENE_QUERY.equals(propertyName) || NATIVE_SOLR_QUERY.equals(propertyName)) &&
+                (!configuration.useForPropertyRestrictions() // Solr index not used for properties
+                        || (configuration.getUsedProperties().size() > 0 && !configuration.getUsedProperties().contains(propertyName)) // not explicitly contained in the used properties
+                        || propertyName.contains("/") // no child-level property restrictions
+                        || "rep:excerpt".equals(propertyName) // rep:excerpt is handled by the query engine
+                        || configuration.getIgnoredProperties().contains(propertyName));
     }
 
     static class SolrResultRow {

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/schema.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/schema.xml?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/schema.xml (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/schema.xml Mon Mar  9 12:21:49 2015
@@ -71,6 +71,13 @@
                 <filter class="solr.LowerCaseFilterFactory"/>
             </analyzer>
         </fieldType>
+        <fieldType name="textSpell" class="solr.TextField" positionIncrementGap="100" >
+            <analyzer>
+                <tokenizer class="solr.StandardTokenizerFactory"/>
+                <filter class="solr.LowerCaseFilterFactory"/>
+                <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
+            </analyzer>
+        </fieldType>
 
         <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
 
@@ -108,38 +115,16 @@
         <field name=":path" type="string" indexed="true" stored="false" />
         <field name="_version_" type="long" indexed="true" stored="true"/>
 
-    <dynamicField name="*_i"  type="int"    indexed="true"  stored="true"/>
-    <dynamicField name="*_is" type="int"    indexed="true"  stored="true"  multiValued="true"/>
-    <dynamicField name="*_s"  type="string"  indexed="true"  stored="true" />
-    <dynamicField name="*_ss" type="string"  indexed="true"  stored="true" multiValued="true"/>
-    <dynamicField name="*_l"  type="long"   indexed="true"  stored="true"/>
-    <dynamicField name="*_ls" type="long"   indexed="true"  stored="true"  multiValued="true"/>
-    <dynamicField name="*_t"  type="text_general"    indexed="true"  stored="true"/>
-    <dynamicField name="*_txt" type="text_general"   indexed="true"  stored="true" multiValued="true"/>
-    <dynamicField name="*_b"  type="boolean" indexed="true" stored="true"/>
-    <dynamicField name="*_bs" type="boolean" indexed="true" stored="true"  multiValued="true"/>
-    <dynamicField name="*_f"  type="float"  indexed="true"  stored="true"/>
-    <dynamicField name="*_fs" type="float"  indexed="true"  stored="true"  multiValued="true"/>
-    <dynamicField name="*_d"  type="double" indexed="true"  stored="true"/>
-    <dynamicField name="*_ds" type="double" indexed="true"  stored="true"  multiValued="true"/>
-
-    <dynamicField name="*_dt"  type="date"    indexed="true"  stored="true"/>
-    <dynamicField name="*_dts" type="date"    indexed="true"  stored="true" multiValued="true"/>
-
-    <dynamicField name="*_ti" type="tint"    indexed="true"  stored="true"/>
-    <dynamicField name="*_tl" type="tlong"   indexed="true"  stored="true"/>
-    <dynamicField name="*_tf" type="tfloat"  indexed="true"  stored="true"/>
-    <dynamicField name="*_td" type="tdouble" indexed="true"  stored="true"/>
-    <dynamicField name="*_tdt" type="tdate"  indexed="true"  stored="true"/>
-
-    <dynamicField name="*_pi"  type="pint"    indexed="true"  stored="true"/>
-    <dynamicField name="*_c"   type="currency" indexed="true"  stored="true"/>
-    <dynamicField name="*" type="text_general" indexed="true" stored="true" multiValued="true"/>
-  </fields>
-  <uniqueKey>path_exact</uniqueKey>
-  <copyField source="path_exact" dest="path_anc"/>
-  <copyField source="path_exact" dest="path_des"/>
-  <copyField source="path_exact" dest="path_child"/>
+        <field name="rep:members" type="string" indexed="true" stored="true" multiValued="true"/>
+        <field name="rep:principalName" type="string" indexed="true" stored="true" multiValued="true"/>
+        <field name=":indexed" type="tdate" indexed="true" stored="false" default="NOW" docValues="numeric"/>
+        <dynamicField name="*_bin" type="string" indexed="true" stored="true" multiValued="true"/>
+        <dynamicField name="*" type="text_general" indexed="true" stored="true" multiValued="true"/>
+    </fields>
+    <uniqueKey>path_exact</uniqueKey>
+    <copyField source="path_exact" dest="path_anc"/>
+    <copyField source="path_exact" dest="path_des"/>
+    <copyField source="path_exact" dest="path_child"/>
     <copyField source="path_exact" dest=":path"/>
   <copyField source="*" dest="catch_all"/>
 </schema>

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml Mon Mar  9 12:21:49 2015
@@ -866,6 +866,10 @@
              <str>nameOfCustomComponent2</str>
            </arr>
           -->
+        <arr name="last-components">
+            <str>mlt</str>
+            <str>spellcheck</str>
+        </arr>
     </requestHandler>
 
     <!-- A request handler that returns indented JSON by default -->
@@ -1163,6 +1167,65 @@
       -->
 
 
+    <searchComponent name="spellcheck" class="solr.SpellCheckComponent">
+
+        <str name="queryAnalyzerFieldType">text_general</str>
+
+        <!-- Multiple "Spell Checkers" can be declared and used by this
+           component
+        -->
+
+        <!-- a spellchecker built from a field of the main index -->
+        <lst name="spellchecker">
+            <str name="name">default</str>
+            <str name="field">catch_all</str>
+            <str name="classname">solr.DirectSolrSpellChecker</str>
+            <str name="distanceMeasure">internal</str>
+            <!-- minimum accuracy needed to be considered a valid spellcheck suggestion -->
+            <float name="accuracy">0.5</float>
+            <!-- the maximum #edits we consider when enumerating terms: can be 1 or 2 -->
+            <int name="maxEdits">2</int>
+            <!-- the minimum shared prefix when enumerating terms -->
+            <int name="minPrefix">1</int>
+            <!-- maximum number of inspections per result. -->
+            <int name="maxInspections">5</int>
+            <!-- minimum length of a query term to be considered for correction -->
+            <int name="minQueryLength">4</int>
+            <!-- maximum threshold of documents a query term can appear to be considered for correction -->
+            <float name="maxQueryFrequency">0.01</float>
+        </lst>
+
+        <lst name="spellchecker">
+            <str name="name">wordbreak</str>
+            <str name="classname">solr.WordBreakSolrSpellChecker</str>
+            <str name="field">name</str>
+            <str name="combineWords">true</str>
+            <str name="breakWords">true</str>
+            <int name="maxChanges">10</int>
+        </lst>
+
+    </searchComponent>
+
+    <requestHandler name="/spellcheck" class="solr.SearchHandler" startup="lazy">
+        <lst name="defaults">
+            <str name="df">catch_all</str>
+            <str name="spellcheck.dictionary">default</str>
+            <str name="spellcheck.dictionary">wordbreak</str>
+            <str name="spellcheck">on</str>
+            <str name="spellcheck.extendedResults">true</str>
+            <str name="spellcheck.count">10</str>
+            <str name="spellcheck.alternativeTermCount">5</str>
+            <str name="spellcheck.maxResultsForSuggest">5</str>
+            <str name="spellcheck.collate">true</str>
+            <str name="spellcheck.collateExtendedResults">true</str>
+            <str name="spellcheck.maxCollationTries">10</str>
+            <str name="spellcheck.maxCollations">5</str>
+        </lst>
+        <arr name="last-components">
+            <str>spellcheck</str>
+        </arr>
+    </requestHandler>
+
     <!-- Update Processors
 
          Chains of Update Processor Factories for dealing with Update

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTestIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTestIT.java?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTestIT.java (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTestIT.java Mon Mar  9 12:21:49 2015
@@ -88,6 +88,11 @@ public class SolrIndexQueryTestIT extend
     }
 
     @Test
+    public void sql1() throws Exception {
+        test("sql1.txt");
+    }
+
+    @Test
     public void sql2() throws Exception {
         test("sql2.txt");
     }

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/schema.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/schema.xml?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/schema.xml (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/schema.xml Mon Mar  9 12:21:49 2015
@@ -70,6 +70,13 @@
                 <filter class="solr.LowerCaseFilterFactory"/>
             </analyzer>
         </fieldType>
+        <fieldType name="textSpell" class="solr.TextField" positionIncrementGap="100" >
+            <analyzer>
+                <tokenizer class="solr.StandardTokenizerFactory"/>
+                <filter class="solr.LowerCaseFilterFactory"/>
+                <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
+            </analyzer>
+        </fieldType>
 
         <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
 
@@ -113,6 +120,7 @@
         <field name="catch_all" type="text_general" indexed="true" stored="false" multiValued="true" termVectors="true"/> <!-- term vectors used for rep:similar -->
         <field name="_version_" type="long" indexed="true" stored="true"/>
         <field name=":path" type="string" indexed="true" stored="false"/>
+        <field name=":indexed" type="tdate" indexed="true" stored="false" default="NOW" docValues="numeric"/>
 
         <field name="jcr:data" type="binary"  indexed="true"  stored="false" multiValued="true"/>
         <dynamicField name="*_i"  type="int"    indexed="true"  stored="true"/>

Modified: jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml?rev=1665206&r1=1665205&r2=1665206&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml (original)
+++ jackrabbit/oak/branches/1.0/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml Mon Mar  9 12:21:49 2015
@@ -808,6 +808,10 @@ Lucene will flush based on whichever lim
            <str>nameOfCustomComponent2</str>
          </arr>
         -->
+        <arr name="last-components">
+            <str>mlt</str>
+            <str>spellcheck</str>
+        </arr>
     </requestHandler>
 
     <!-- A request handler that returns indented JSON by default -->
@@ -1196,7 +1200,7 @@ current implementation relies on the upd
     -->
     <searchComponent name="spellcheck" class="solr.SpellCheckComponent">
 
-        <str name="queryAnalyzerFieldType">textSpell</str>
+        <str name="queryAnalyzerFieldType">text_general</str>
 
         <!-- Multiple "Spell Checkers" can be declared and used by this
            component
@@ -1205,7 +1209,7 @@ current implementation relies on the upd
         <!-- a spellchecker built from a field of the main index -->
         <lst name="spellchecker">
             <str name="name">default</str>
-            <str name="field">name</str>
+            <str name="field">catch_all</str>
             <str name="classname">solr.DirectSolrSpellChecker</str>
             <!-- the spellcheck distance measure used, the default is the internal levenshtein -->
             <str name="distanceMeasure">internal</str>
@@ -1221,9 +1225,7 @@ current implementation relies on the upd
             <int name="minQueryLength">4</int>
             <!-- maximum threshold of documents a query term can appear to be considered for correction -->
             <float name="maxQueryFrequency">0.01</float>
-            <!-- uncomment this to require suggestions to occur in 1% of the documents
-                <float name="thresholdTokenFrequency">.01</float>
-            -->
+
         </lst>
 
         <!-- a spellchecker that can break or combine words.  See "/spell" handler below for usage -->
@@ -1288,9 +1290,9 @@ current implementation relies on the upd
        See http://wiki.apache.org/solr/SpellCheckComponent for details
        on the request parameters.
     -->
-    <requestHandler name="/spell" class="solr.SearchHandler" startup="lazy">
+    <requestHandler name="/spellcheck" class="solr.SearchHandler" startup="lazy">
         <lst name="defaults">
-            <str name="df">text</str>
+            <str name="df">catch_all</str>
             <!-- Solr will use suggestions from both the 'default' spellchecker
         and from the 'wordbreak' spellchecker and combine them.
         collations (re-written queries) can include a combination of