├── .gitignore ├── LICENSE.md ├── README.md ├── pom.xml └── src ├── main ├── java │ ├── LuceneSql.g4 │ └── bbejeck │ │ └── sql │ │ ├── antlr │ │ ├── LuceneQueryParser.java │ │ └── generated │ │ │ ├── LuceneSql.tokens │ │ │ ├── LuceneSqlBaseListener.java │ │ │ ├── LuceneSqlBaseVisitor.java │ │ │ ├── LuceneSqlLexer.java │ │ │ ├── LuceneSqlLexer.tokens │ │ │ ├── LuceneSqlListener.java │ │ │ ├── LuceneSqlParser.java │ │ │ └── LuceneSqlVisitor.java │ │ ├── lucene │ │ ├── BooleanClauseBuilder.java │ │ ├── FilterType.java │ │ ├── LuceneAnalyzingFunctions.java │ │ ├── LuceneQueryAssembler.java │ │ ├── LuceneQueryFunctions.java │ │ ├── LuceneQueryListener.java │ │ ├── LuceneQueryVisitor.java │ │ ├── QueryParseResults.java │ │ ├── QueryType.java │ │ └── Searcher.java │ │ └── util │ │ ├── Collectors.java │ │ ├── Tester.java │ │ ├── ThrowingBiFunction.java │ │ └── ThrowingFunction.java └── resources │ └── names.csv └── test ├── FakeNameGenerator.com_d5d6d718.csv ├── java └── bbejeck │ └── sql │ └── lucene │ ├── LuceneQueryFunctionsTest.java │ ├── LuceneQueryParsingTest.java │ ├── LuceneQuerySearchTest.java │ ├── LuceneSqlFileSystemSearchBase.java │ ├── LuceneSqlSearchBase.java │ ├── QueryTypeTest.java │ ├── SearcherFileSystemIndexTest.java │ └── SearcherTest.java └── small_values.csv /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 4 | 5 | *.iml 6 | 7 | ## Directory-based project format: 8 | .idea/ 9 | # if you remove the above rule, at least ignore the following: 10 | 11 | # User-specific stuff: 12 | # .idea/workspace.xml 13 | # .idea/tasks.xml 14 | # .idea/dictionaries 15 | 16 | # Sensitive or high-churn files: 17 | # .idea/dataSources.ids 18 | # .idea/dataSources.xml 19 | # .idea/sqlDataSources.xml 20 | # .idea/dynamic.xml 21 | # .idea/uiDesigner.xml 22 | 23 | # Gradle: 24 | # .idea/gradle.xml 25 | # .idea/libraries 26 | 27 | # Mongo Explorer plugin: 28 | # .idea/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.ipr 32 | *.iws 33 | 34 | ## Plugin-specific files: 35 | 36 | # IntelliJ 37 | out/ 38 | 39 | # mpeltonen/sbt-idea plugin 40 | .idea_modules/ 41 | 42 | # JIRA plugin 43 | atlassian-ide-plugin.xml 44 | 45 | # Crashlytics plugin (for Android Studio and IntelliJ) 46 | com_crashlytics_export_strings.xml 47 | crashlytics.properties 48 | crashlytics-build.properties 49 | 50 | 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Sql for Lucene ## 2 | 3 | Originally a side project, I've decided to put this out there in case someone else 4 | may find this useful. 5 | 6 | ### Introduction 7 | The `LuceneSqlParser` supports a subset of standard sql. Here are some examples: 8 | 9 | ``` 10 | Select last_name from '/path/to/index/' where first_name='Foo' and age <=30 and city='Boston' limit 25 11 | 12 | Select * from 'path/index/' where age in (31, 30, 50) 13 | 14 | Select first_name, last_name from '/path/index/' where city in ('Cincinatti', 'New York', 'Boyds') 15 | 16 | Select first_name from '/path/index/' where age between 35 and 50 and first_name like 'Br*' 17 | -- Also takes paths from Windows OS 18 | Select first_name from 'C:/path/index/' where first_name='John' and (age<=45 and city not in ('New York', 'Boston', 'Atlanta')) 19 | ``` 20 | 21 | The `LuceneSqlParser` returns a [BooleanQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/BooleanQuery.html). The `BooleanQuery` will contain different types of lucene query objects depending on the predicates used. There is a class `Searcher` avaiable for use with the `LuceneSqlParser`. The `Searcher` abstracts away the opening of a lucene [IndexSearcher](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/IndexSearcher.html), iterating over the [ScoreDoc](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/ScoreDoc.html) array and extracting results. Next, we'll take a look at the rules used to parse the sql. 22 | 23 | ### LuceneSqlParser Functionality 24 | At high level a sql statement is broken down and parsed in the following manner: 25 | 26 | 1. The 'Select' statement contains a comma sparated list of fields stored in a Lucene index. The parser stores fields in a `Set` for use by the `Searcher`. To retreive all fields we can specify a '*' operator, or omit the 'select' clause altogether. 27 | 2. The 'From' clause takes a path in single quotes representing the location of a lucene index. 28 | 3. The 'Where' clause contains the predicates for searching the data. 29 | 4. The parser analyzes values used for searching in a similar fashion as the [StandardAnalyzer](http://lucene.apache.org/core/5_0_0/analyzers-common/org/apache/lucene/analysis/standard/StandardAnalyzer.html) (lower cased, whitespace and special characters removed). There are exceptions to this rule. The [PrefixQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/PrefixQuery.html), [RegexQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/RegexpQuery.html) and the [WildcardQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/WildcardQuery.html) are special cases and only removes characters not defined as special characters used by Lucene. 30 | 5. Predicates can be nested to an arbitrary depth. For example: `where field='1' and (field2='2' and field3='3' and (field4='4' and (field5='5' and field='6')))` 31 | 6. The 'Select' and 'From' clauses are optional. 32 | 33 | The `LuceneQueryParser` defines two static methods `parseQuery` and `parseToBooleanQuery`. The `parseQuery` method is intended to be used in conjuction with the `Searcher`. The `parseQuery` returns a `QueryParseResults` object that contains the path for the index, the set of fields to retrieve and the `BooleanQuery` to execute. The `parseToBooleanQuery` is intended to be used for parsing only and returns a `BooleanQuery`. 34 | 35 | ### SQL to Lucene Query Functionality Mapping 36 | We now will list the supported Lucene query objects and how they are mapped from the input sql. 37 | 38 | * ` ='Foo'` converts to a [TermQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/TermQuery.html). 39 | * ` ='Bar Baz'` converts to a [PhraseQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/PhraseQuery.html) 40 | * ` like 'Fo*'` converts to a `PrefixQuery` 41 | * ` like 'B?l?'` converts to a `WildcardQuery` 42 | * ` matches('[Bb].*[hH]?')` converts to a `RegexpQuery` 43 | * ` in ('foo', 'bar', 'baz')` converts to a `BooleanQuery` consisting of 3 [BooleanClause](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/BooleanClause.html) objects. Each clause is a `TermQuery` with a [BooleanClause.Occur](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/BooleanClause.Occur.html) of `SHOULD`. 44 | * `PhraseQuery` and `TermQuery` objects can be combined in the 'in' operator. For example `city in ('New York', 'Boston', 'Los Angeles')` 45 | * `between 'Foo' AND 'Bar'` converts to a [TermRangeQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/TermRangeQuery.html) with both items being inclusive. 46 | * `between 25 and 40` converts to a [NumericRangeQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/NumericRangeQuery.html) again inclusive. 47 | * The >, <, >= <= operators are converted to either `TermRangeQuery` or `NumericRangeQuery` objects with one side of the range being unbounded. The < and > operators are exclusive. The <= and >= operators are inclusive. 48 | 49 | The AND,OR & NOT operators are mappped in the following manner. 50 | 51 | * AND converts to `BooleanClause.Occur.MUST` 52 | * OR converts to `BooleanClause.Occur.SHOULD` 53 | * NOT converts to `BooleanClause.Occur.MUST_NOT` 54 | 55 | ### Optimizations 56 | In two cases the query is converted to something different from the mappings shown previously. The first case is a query that contains a single predicate that *must not* match. For example: 57 | 58 | ``` 59 | Select * from /index/path/ where last_name != 'Smith' 60 | Select first_name, last_name where city not in ('Foo', 'Bar') 61 | ``` 62 | A query submitted in this format will not work in lucene. This fix for this query is simple. The parser takes the original `BooleanQuery` and adds an addtional clause. The underlying query object in the new clause is a [MatchAllDocsQuery](http://lucene.apache.org/core/5_0_0/core/org/apache/lucene/search/MatchAllDocsQuery.html). The `MatchAllDocsQuery` returns all documents in the index and the orginal predicate will fiter out the unwanted results. The second case is when searching for a numeric field in the `TermQuery` format. For example: 63 | 64 | ``` 65 | Select * from '/index/path' where age = 49 66 | ``` 67 | 68 | Normally a 'field=value' or 'field != value' predicate is converted to a `TermQuery`. But the way lucene searches for values it will not find a field if it is searching for a number versus a string. In this case the parser constructs a `NumericRangeQuery` where the low and high value are equal and inclusive. 69 | 70 | ### Limitations 71 | There are a several limitations at this point. 72 | 73 | * Converting to a `PhraseQuery` does not allow for specifying any [slop](http://lucene.apache.org/core/4_10_2/core/org/apache/lucene/search/PhraseQuery.html#setSlop\(int\)). For a match with a `PhraseQuery` all terms must be located adjacent to each other. 74 | * Numeric type queries only support the Int type for now. 75 | * Range querries are inclusive when both a high and low value are specified. 76 | * If no limit clause is specified in the query, a default limit of 10,000 records is used. 77 | 78 | ### Searcher 79 | 80 | The second component of sql for lucene is the `Searcher`class. The `Searcher` could be thought of as a convenience method for performing a lucene search and extracting the results. The `Searcher` has one method `search` that takes a sql query and returns a `List>` containing the search results. Each map in the list represents a document with the keys being the field names and the values are the values stored in the retrieved fields. 81 | 82 | ``` 83 | String query = "Select age,city from '/path/to/index/' where first_name='john' and age='50'"; 84 | List> results = searcher.search(query); 85 | ``` 86 | It's worth noting the list and map returned from the searcher are of type [ImmutableList](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableList.html) and [ImmutableMap](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableMap.html) respectively. The `Searcher` has 4 constructors: 87 | 88 | ``` 89 | 90 | public Searcher() {} 91 | 92 | public Searcher(String indexPath){ 93 | Preconditions.checkArgument(indexPath != null && !indexPath.trim().isEmpty(), "Index Path is can't be null or empty"); 94 | this.indexSearcher = createIndexSearcherFromStringPath.apply(indexPath); 95 | } 96 | 97 | public Searcher(Path indexPath){ 98 | Preconditions.checkNotNull(indexPath,"Index Path can't be null"); 99 | this.indexSearcher = createIndexSearcherFromPath.apply(indexPath); 100 | } 101 | 102 | public Searcher(Directory directory) { 103 | Preconditions.checkNotNull(directory,"Directory can't be null"); 104 | this.indexSearcher = fromDirectoryToIndexSearcher.apply(directory); 105 | } 106 | 107 | ``` 108 | If the searcher is instantiated with the no-arg constructor, then the path for the index will be extracted from the query and used to open the `IndexSearcher`. All subsequent queries can safely omit the from clause. If the searcher is instantiated with any of the other 3 constructors, the 'from' clause will be ignored and can be omitted from the query. 109 | 110 | ### Features To Be Added 111 | 112 | * A JDBC Driver. 113 | * Insert, Update and Delete support. 114 | * Support all the numeric types supported by Lucene. 115 | * Syntax to support `FuzzyQuery` searches. 116 | * Support for filters. 117 | * Ability to specify *slop* for `PhraseQuery` searches. 118 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 21 | 22 | 24 | 4.0.0 25 | 26 | bbejeck.sql 27 | sql-for-lucene 28 | 1.0-SNAPSHOT 29 | jar 30 | 31 | sql-for-lucene 32 | http://maven.apache.org 33 | 34 | 35 | UTF-8 36 | 37 | 38 | 39 | 40 | com.google.guava 41 | guava 42 | 18.0 43 | 44 | 45 | org.apache.lucene 46 | lucene-core 47 | 5.0.0 48 | 49 | 50 | org.apache.lucene 51 | lucene-test-framework 52 | 5.0.0 53 | 54 | 55 | org.apache.lucene 56 | lucene-queryparser 57 | 5.0.0 58 | 59 | 60 | org.apache.lucene 61 | lucene-analyzers-common 62 | 5.0.0 63 | 64 | 65 | org.antlr 66 | antlr4 67 | 4.5 68 | 69 | 70 | org.codehaus.groovy 71 | groovy 72 | 2.0.0 73 | test 74 | 75 | 76 | org.spockframework 77 | spock-core 78 | 0.7-groovy-2.0 79 | test 80 | 81 | 82 | junit 83 | junit 84 | 4.11 85 | test 86 | 87 | 88 | 89 | 90 | 91 | 106 | 107 | org.apache.maven.plugins 108 | maven-compiler-plugin 109 | 2.0.2 110 | 111 | 1.8 112 | 1.8 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/main/java/LuceneSql.g4: -------------------------------------------------------------------------------- 1 | grammar LuceneSql; 2 | 3 | query : select_stmt? from_stmt? where_stmt limit_stmt? 4 | ; 5 | 6 | select_stmt : SELECT (SPLAT | (FIELD (COMMA FIELD)*)); 7 | 8 | from_stmt : FROM PATH 9 | ; 10 | 11 | where_stmt : WHERE search_condition+ 12 | ; 13 | 14 | limit_stmt : LIMIT NUMBER 15 | ; 16 | 17 | search_condition : predicate (predicate | nested_predicate) * 18 | ; 19 | 20 | predicate : boolean_op? (comparison_predicate | function_predicate) 21 | ; 22 | 23 | comparison_predicate : field (comparison_op value | range_op ) 24 | ; 25 | 26 | function_predicate : regexp | between | like | in 27 | ; 28 | 29 | field : FIELD 30 | ; 31 | 32 | comparison_op : EQ # Equals 33 | | NE # NotEqual 34 | ; 35 | 36 | range_op : greater_than 37 | | greater_than_equals 38 | | less_than 39 | | less_than_equals 40 | ; 41 | 42 | 43 | greater_than : GT NUMBER #greaterThanNumber 44 | | GT TERM #greaterThanTerm 45 | | GT DATE #greaterThanDate 46 | ; 47 | 48 | greater_than_equals : GTE NUMBER #greaterThanEqNumber 49 | | GTE TERM #greaterThanEqTerm 50 | | GTE DATE #greaterThanEqDate 51 | ; 52 | 53 | less_than : LT NUMBER #lessThanNumber 54 | | LT TERM #lessThanTerm 55 | | LT DATE #lessThanDate 56 | ; 57 | 58 | less_than_equals : LTE NUMBER #lessThanEqNumber 59 | | LTE TERM #lessThanEqTerm 60 | | LTE DATE #lessThanEqDate 61 | ; 62 | 63 | 64 | boolean_op : AND # And 65 | | OR # Or 66 | | NOT # Not 67 | | AND NOT # AndNot 68 | | OR NOT # OrNot 69 | ; 70 | 71 | nested_predicate : boolean_op? LPAREN predicate (predicate | nested_predicate)* RPAREN 72 | ; 73 | 74 | 75 | value : NUMBER # Number 76 | | TERM # Term 77 | | PHRASE # Phrase 78 | | DATE # Date 79 | | MULTI_PHRASE # MULTI_PHRASE 80 | ; 81 | 82 | regexp : field MATCHES LPAREN WILD_CARD RPAREN 83 | ; 84 | 85 | between : between_number | between_term 86 | ; 87 | 88 | between_term : field BETWEEN TERM AND TERM 89 | ; 90 | 91 | between_number : field BETWEEN NUMBER AND NUMBER 92 | ; 93 | 94 | like : field LIKE WILD_CARD 95 | ; 96 | 97 | in : field NOT? IN value_list 98 | ; 99 | 100 | value_list : LPAREN (number_list | date_list | term_list | phrase_list ) RPAREN 101 | ; 102 | 103 | number_list : NUMBER (COMMA NUMBER)* 104 | ; 105 | 106 | date_list : DATE (COMMA DATE)* 107 | ; 108 | 109 | term_list : TERM (COMMA TERM)* 110 | ; 111 | 112 | phrase_list : (TERM | PHRASE) ( COMMA (TERM | PHRASE) ) * 113 | ; 114 | //Parser Rules End 115 | 116 | //Lexer Rules Start 117 | SELECT : [Ss][Ee][Ll][Ee][Cc][Tt] ; 118 | FROM : [Ff][Rr][Oo][Mm] ; 119 | WHERE : [Ww][Hh][Ee][Rr][Ee] ; 120 | AND : [Aa][Nn][Dd] ; 121 | OR : [Oo][Rr] ; 122 | NOT : [Nn][Oo][Tt] ; 123 | DESCRIBE : [Dd][Ee][Ss][Cc][Rr][Ii][Bb][Ee] ; 124 | MATCHES : [Mm][Aa][Tt][Cc][Hh][Ee][Ss] ; 125 | BETWEEN : [Bb][Ee][Tt][Ww][Ee][Ee][Nn] ; 126 | LIKE : [Ll][Ii][Kk][Ee] ; 127 | LIMIT : [Ll][Ii][Mm][Ii][Tt] ; 128 | EQ : '=' ; 129 | NE : '!='; 130 | GT : '>' ; 131 | LT : '<' ; 132 | GTE : '>=' ; 133 | LTE : '<=' ; 134 | IN : [Ii][Nn]; 135 | SPLAT : '*'; 136 | fragment 137 | DIGIT : [0-9] ; 138 | NUMBER : DIGIT(DIGIT*) ; 139 | fragment 140 | DATE_SEP : [-/] ; 141 | DATE : (NUMBER+(DATE_SEP)?)+; 142 | FIELD : [A-Za-z]+((':'|'_')[0-9]*[A-Za-z]*)* ; 143 | PATH : '\''([A-Za-z]':')?('/')?((~[/])+'/')+ '\''; 144 | TERM : '\''(~[' *?])*'\'' ; 145 | PHRASE : '\''(~['*?])*'\'' ; 146 | WILD_CARD :'\''(~[' ])*'\'' ; 147 | MULTI_PHRASE : '\''(~[' *?])+(~['])+'\''; 148 | DB_QUOTE_STRING_LIT : ('"'(~["])*'"'); 149 | //STRING_LIT : ('\''(~['])*'\'') ; 150 | 151 | COMMA : ',' ; 152 | LPAREN : '(' ; 153 | RPAREN : ')' ; 154 | WS : [ \t\r\n]+ -> skip; 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/LuceneQueryParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.antlr; 23 | 24 | import bbejeck.sql.antlr.generated.LuceneSqlLexer; 25 | import bbejeck.sql.antlr.generated.LuceneSqlParser; 26 | import bbejeck.sql.lucene.LuceneQueryListener; 27 | import bbejeck.sql.lucene.QueryParseResults; 28 | import org.antlr.v4.runtime.ANTLRInputStream; 29 | import org.antlr.v4.runtime.CommonTokenStream; 30 | import org.antlr.v4.runtime.tree.ParseTree; 31 | import org.antlr.v4.runtime.tree.ParseTreeWalker; 32 | import org.apache.lucene.search.BooleanQuery; 33 | 34 | import java.util.function.Function; 35 | import java.util.function.Supplier; 36 | 37 | /** ` 38 | * User: Bill Bejeck 39 | * Date: 10/14/14 40 | * Time: 10:10 PM 41 | */ 42 | public class LuceneQueryParser { 43 | 44 | private static Function createAntlrInputStream = ANTLRInputStream::new; 45 | private static Function createLexer = LuceneSqlLexer::new; 46 | private static Function createTokenStream = CommonTokenStream::new; 47 | private static Function createLuceneSqlParser = LuceneSqlParser::new; 48 | private static Function createParseTree = LuceneSqlParser::query; 49 | private static Supplier parseTreeWalkerSupplier = ParseTreeWalker::new; 50 | private static Supplier luceneQueryListenerSupplier = LuceneQueryListener::new; 51 | 52 | private static Function createParser = createAntlrInputStream 53 | .andThen(createLexer) 54 | .andThen(createTokenStream) 55 | .andThen(createLuceneSqlParser); 56 | 57 | private static Function parse = parser -> { 58 | LuceneQueryListener listener = luceneQueryListenerSupplier.get(); 59 | ParseTree parseTree = createParseTree.apply(parser); 60 | ParseTreeWalker walker = parseTreeWalkerSupplier.get(); 61 | walker.walk(listener, parseTree); 62 | return listener.getParseResults(); 63 | }; 64 | 65 | 66 | public static QueryParseResults parseQuery(String query) { 67 | return parse.apply(createParser.apply(query)); 68 | } 69 | 70 | public static BooleanQuery parseToBooleanQuery(String query) { 71 | return parseQuery(query).getBooleanQuery(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/generated/LuceneSql.tokens: -------------------------------------------------------------------------------- 1 | SELECT=1 2 | FROM=2 3 | WHERE=3 4 | AND=4 5 | OR=5 6 | NOT=6 7 | DESCRIBE=7 8 | MATCHES=8 9 | BETWEEN=9 10 | LIKE=10 11 | LIMIT=11 12 | EQ=12 13 | NE=13 14 | GT=14 15 | LT=15 16 | GTE=16 17 | LTE=17 18 | IN=18 19 | SPLAT=19 20 | NUMBER=20 21 | DATE=21 22 | FIELD=22 23 | PATH=23 24 | TERM=24 25 | PHRASE=25 26 | WILD_CARD=26 27 | MULTI_PHRASE=27 28 | DB_QUOTE_STRING_LIT=28 29 | COMMA=29 30 | LPAREN=30 31 | RPAREN=31 32 | WS=32 33 | '='=12 34 | '!='=13 35 | '>'=14 36 | '<'=15 37 | '>='=16 38 | '<='=17 39 | '*'=19 40 | ','=29 41 | '('=30 42 | ')'=31 43 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/generated/LuceneSqlBaseListener.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/bbejeck/dev/github_clones/sql-for-lucene/src/main/java/LuceneSql.g4 by ANTLR 4.5.1 2 | package bbejeck.sql.antlr.generated; 3 | 4 | import org.antlr.v4.runtime.ParserRuleContext; 5 | import org.antlr.v4.runtime.tree.ErrorNode; 6 | import org.antlr.v4.runtime.tree.TerminalNode; 7 | 8 | /** 9 | * This class provides an empty implementation of {@link LuceneSqlListener}, 10 | * which can be extended to create a listener which only needs to handle a subset 11 | * of the available methods. 12 | */ 13 | public class LuceneSqlBaseListener implements LuceneSqlListener { 14 | /** 15 | * {@inheritDoc} 16 | * 17 | *

The default implementation does nothing.

18 | */ 19 | @Override public void enterQuery(LuceneSqlParser.QueryContext ctx) { } 20 | /** 21 | * {@inheritDoc} 22 | * 23 | *

The default implementation does nothing.

24 | */ 25 | @Override public void exitQuery(LuceneSqlParser.QueryContext ctx) { } 26 | /** 27 | * {@inheritDoc} 28 | * 29 | *

The default implementation does nothing.

30 | */ 31 | @Override public void enterSelect_stmt(LuceneSqlParser.Select_stmtContext ctx) { } 32 | /** 33 | * {@inheritDoc} 34 | * 35 | *

The default implementation does nothing.

36 | */ 37 | @Override public void exitSelect_stmt(LuceneSqlParser.Select_stmtContext ctx) { } 38 | /** 39 | * {@inheritDoc} 40 | * 41 | *

The default implementation does nothing.

42 | */ 43 | @Override public void enterFrom_stmt(LuceneSqlParser.From_stmtContext ctx) { } 44 | /** 45 | * {@inheritDoc} 46 | * 47 | *

The default implementation does nothing.

48 | */ 49 | @Override public void exitFrom_stmt(LuceneSqlParser.From_stmtContext ctx) { } 50 | /** 51 | * {@inheritDoc} 52 | * 53 | *

The default implementation does nothing.

54 | */ 55 | @Override public void enterWhere_stmt(LuceneSqlParser.Where_stmtContext ctx) { } 56 | /** 57 | * {@inheritDoc} 58 | * 59 | *

The default implementation does nothing.

60 | */ 61 | @Override public void exitWhere_stmt(LuceneSqlParser.Where_stmtContext ctx) { } 62 | /** 63 | * {@inheritDoc} 64 | * 65 | *

The default implementation does nothing.

66 | */ 67 | @Override public void enterLimit_stmt(LuceneSqlParser.Limit_stmtContext ctx) { } 68 | /** 69 | * {@inheritDoc} 70 | * 71 | *

The default implementation does nothing.

72 | */ 73 | @Override public void exitLimit_stmt(LuceneSqlParser.Limit_stmtContext ctx) { } 74 | /** 75 | * {@inheritDoc} 76 | * 77 | *

The default implementation does nothing.

78 | */ 79 | @Override public void enterSearch_condition(LuceneSqlParser.Search_conditionContext ctx) { } 80 | /** 81 | * {@inheritDoc} 82 | * 83 | *

The default implementation does nothing.

84 | */ 85 | @Override public void exitSearch_condition(LuceneSqlParser.Search_conditionContext ctx) { } 86 | /** 87 | * {@inheritDoc} 88 | * 89 | *

The default implementation does nothing.

90 | */ 91 | @Override public void enterPredicate(LuceneSqlParser.PredicateContext ctx) { } 92 | /** 93 | * {@inheritDoc} 94 | * 95 | *

The default implementation does nothing.

96 | */ 97 | @Override public void exitPredicate(LuceneSqlParser.PredicateContext ctx) { } 98 | /** 99 | * {@inheritDoc} 100 | * 101 | *

The default implementation does nothing.

102 | */ 103 | @Override public void enterComparison_predicate(LuceneSqlParser.Comparison_predicateContext ctx) { } 104 | /** 105 | * {@inheritDoc} 106 | * 107 | *

The default implementation does nothing.

108 | */ 109 | @Override public void exitComparison_predicate(LuceneSqlParser.Comparison_predicateContext ctx) { } 110 | /** 111 | * {@inheritDoc} 112 | * 113 | *

The default implementation does nothing.

114 | */ 115 | @Override public void enterFunction_predicate(LuceneSqlParser.Function_predicateContext ctx) { } 116 | /** 117 | * {@inheritDoc} 118 | * 119 | *

The default implementation does nothing.

120 | */ 121 | @Override public void exitFunction_predicate(LuceneSqlParser.Function_predicateContext ctx) { } 122 | /** 123 | * {@inheritDoc} 124 | * 125 | *

The default implementation does nothing.

126 | */ 127 | @Override public void enterField(LuceneSqlParser.FieldContext ctx) { } 128 | /** 129 | * {@inheritDoc} 130 | * 131 | *

The default implementation does nothing.

132 | */ 133 | @Override public void exitField(LuceneSqlParser.FieldContext ctx) { } 134 | /** 135 | * {@inheritDoc} 136 | * 137 | *

The default implementation does nothing.

138 | */ 139 | @Override public void enterEquals(LuceneSqlParser.EqualsContext ctx) { } 140 | /** 141 | * {@inheritDoc} 142 | * 143 | *

The default implementation does nothing.

144 | */ 145 | @Override public void exitEquals(LuceneSqlParser.EqualsContext ctx) { } 146 | /** 147 | * {@inheritDoc} 148 | * 149 | *

The default implementation does nothing.

150 | */ 151 | @Override public void enterNotEqual(LuceneSqlParser.NotEqualContext ctx) { } 152 | /** 153 | * {@inheritDoc} 154 | * 155 | *

The default implementation does nothing.

156 | */ 157 | @Override public void exitNotEqual(LuceneSqlParser.NotEqualContext ctx) { } 158 | /** 159 | * {@inheritDoc} 160 | * 161 | *

The default implementation does nothing.

162 | */ 163 | @Override public void enterRange_op(LuceneSqlParser.Range_opContext ctx) { } 164 | /** 165 | * {@inheritDoc} 166 | * 167 | *

The default implementation does nothing.

168 | */ 169 | @Override public void exitRange_op(LuceneSqlParser.Range_opContext ctx) { } 170 | /** 171 | * {@inheritDoc} 172 | * 173 | *

The default implementation does nothing.

174 | */ 175 | @Override public void enterGreaterThanNumber(LuceneSqlParser.GreaterThanNumberContext ctx) { } 176 | /** 177 | * {@inheritDoc} 178 | * 179 | *

The default implementation does nothing.

180 | */ 181 | @Override public void exitGreaterThanNumber(LuceneSqlParser.GreaterThanNumberContext ctx) { } 182 | /** 183 | * {@inheritDoc} 184 | * 185 | *

The default implementation does nothing.

186 | */ 187 | @Override public void enterGreaterThanTerm(LuceneSqlParser.GreaterThanTermContext ctx) { } 188 | /** 189 | * {@inheritDoc} 190 | * 191 | *

The default implementation does nothing.

192 | */ 193 | @Override public void exitGreaterThanTerm(LuceneSqlParser.GreaterThanTermContext ctx) { } 194 | /** 195 | * {@inheritDoc} 196 | * 197 | *

The default implementation does nothing.

198 | */ 199 | @Override public void enterGreaterThanDate(LuceneSqlParser.GreaterThanDateContext ctx) { } 200 | /** 201 | * {@inheritDoc} 202 | * 203 | *

The default implementation does nothing.

204 | */ 205 | @Override public void exitGreaterThanDate(LuceneSqlParser.GreaterThanDateContext ctx) { } 206 | /** 207 | * {@inheritDoc} 208 | * 209 | *

The default implementation does nothing.

210 | */ 211 | @Override public void enterGreaterThanEqNumber(LuceneSqlParser.GreaterThanEqNumberContext ctx) { } 212 | /** 213 | * {@inheritDoc} 214 | * 215 | *

The default implementation does nothing.

216 | */ 217 | @Override public void exitGreaterThanEqNumber(LuceneSqlParser.GreaterThanEqNumberContext ctx) { } 218 | /** 219 | * {@inheritDoc} 220 | * 221 | *

The default implementation does nothing.

222 | */ 223 | @Override public void enterGreaterThanEqTerm(LuceneSqlParser.GreaterThanEqTermContext ctx) { } 224 | /** 225 | * {@inheritDoc} 226 | * 227 | *

The default implementation does nothing.

228 | */ 229 | @Override public void exitGreaterThanEqTerm(LuceneSqlParser.GreaterThanEqTermContext ctx) { } 230 | /** 231 | * {@inheritDoc} 232 | * 233 | *

The default implementation does nothing.

234 | */ 235 | @Override public void enterGreaterThanEqDate(LuceneSqlParser.GreaterThanEqDateContext ctx) { } 236 | /** 237 | * {@inheritDoc} 238 | * 239 | *

The default implementation does nothing.

240 | */ 241 | @Override public void exitGreaterThanEqDate(LuceneSqlParser.GreaterThanEqDateContext ctx) { } 242 | /** 243 | * {@inheritDoc} 244 | * 245 | *

The default implementation does nothing.

246 | */ 247 | @Override public void enterLessThanNumber(LuceneSqlParser.LessThanNumberContext ctx) { } 248 | /** 249 | * {@inheritDoc} 250 | * 251 | *

The default implementation does nothing.

252 | */ 253 | @Override public void exitLessThanNumber(LuceneSqlParser.LessThanNumberContext ctx) { } 254 | /** 255 | * {@inheritDoc} 256 | * 257 | *

The default implementation does nothing.

258 | */ 259 | @Override public void enterLessThanTerm(LuceneSqlParser.LessThanTermContext ctx) { } 260 | /** 261 | * {@inheritDoc} 262 | * 263 | *

The default implementation does nothing.

264 | */ 265 | @Override public void exitLessThanTerm(LuceneSqlParser.LessThanTermContext ctx) { } 266 | /** 267 | * {@inheritDoc} 268 | * 269 | *

The default implementation does nothing.

270 | */ 271 | @Override public void enterLessThanDate(LuceneSqlParser.LessThanDateContext ctx) { } 272 | /** 273 | * {@inheritDoc} 274 | * 275 | *

The default implementation does nothing.

276 | */ 277 | @Override public void exitLessThanDate(LuceneSqlParser.LessThanDateContext ctx) { } 278 | /** 279 | * {@inheritDoc} 280 | * 281 | *

The default implementation does nothing.

282 | */ 283 | @Override public void enterLessThanEqNumber(LuceneSqlParser.LessThanEqNumberContext ctx) { } 284 | /** 285 | * {@inheritDoc} 286 | * 287 | *

The default implementation does nothing.

288 | */ 289 | @Override public void exitLessThanEqNumber(LuceneSqlParser.LessThanEqNumberContext ctx) { } 290 | /** 291 | * {@inheritDoc} 292 | * 293 | *

The default implementation does nothing.

294 | */ 295 | @Override public void enterLessThanEqTerm(LuceneSqlParser.LessThanEqTermContext ctx) { } 296 | /** 297 | * {@inheritDoc} 298 | * 299 | *

The default implementation does nothing.

300 | */ 301 | @Override public void exitLessThanEqTerm(LuceneSqlParser.LessThanEqTermContext ctx) { } 302 | /** 303 | * {@inheritDoc} 304 | * 305 | *

The default implementation does nothing.

306 | */ 307 | @Override public void enterLessThanEqDate(LuceneSqlParser.LessThanEqDateContext ctx) { } 308 | /** 309 | * {@inheritDoc} 310 | * 311 | *

The default implementation does nothing.

312 | */ 313 | @Override public void exitLessThanEqDate(LuceneSqlParser.LessThanEqDateContext ctx) { } 314 | /** 315 | * {@inheritDoc} 316 | * 317 | *

The default implementation does nothing.

318 | */ 319 | @Override public void enterAnd(LuceneSqlParser.AndContext ctx) { } 320 | /** 321 | * {@inheritDoc} 322 | * 323 | *

The default implementation does nothing.

324 | */ 325 | @Override public void exitAnd(LuceneSqlParser.AndContext ctx) { } 326 | /** 327 | * {@inheritDoc} 328 | * 329 | *

The default implementation does nothing.

330 | */ 331 | @Override public void enterOr(LuceneSqlParser.OrContext ctx) { } 332 | /** 333 | * {@inheritDoc} 334 | * 335 | *

The default implementation does nothing.

336 | */ 337 | @Override public void exitOr(LuceneSqlParser.OrContext ctx) { } 338 | /** 339 | * {@inheritDoc} 340 | * 341 | *

The default implementation does nothing.

342 | */ 343 | @Override public void enterNot(LuceneSqlParser.NotContext ctx) { } 344 | /** 345 | * {@inheritDoc} 346 | * 347 | *

The default implementation does nothing.

348 | */ 349 | @Override public void exitNot(LuceneSqlParser.NotContext ctx) { } 350 | /** 351 | * {@inheritDoc} 352 | * 353 | *

The default implementation does nothing.

354 | */ 355 | @Override public void enterAndNot(LuceneSqlParser.AndNotContext ctx) { } 356 | /** 357 | * {@inheritDoc} 358 | * 359 | *

The default implementation does nothing.

360 | */ 361 | @Override public void exitAndNot(LuceneSqlParser.AndNotContext ctx) { } 362 | /** 363 | * {@inheritDoc} 364 | * 365 | *

The default implementation does nothing.

366 | */ 367 | @Override public void enterOrNot(LuceneSqlParser.OrNotContext ctx) { } 368 | /** 369 | * {@inheritDoc} 370 | * 371 | *

The default implementation does nothing.

372 | */ 373 | @Override public void exitOrNot(LuceneSqlParser.OrNotContext ctx) { } 374 | /** 375 | * {@inheritDoc} 376 | * 377 | *

The default implementation does nothing.

378 | */ 379 | @Override public void enterNested_predicate(LuceneSqlParser.Nested_predicateContext ctx) { } 380 | /** 381 | * {@inheritDoc} 382 | * 383 | *

The default implementation does nothing.

384 | */ 385 | @Override public void exitNested_predicate(LuceneSqlParser.Nested_predicateContext ctx) { } 386 | /** 387 | * {@inheritDoc} 388 | * 389 | *

The default implementation does nothing.

390 | */ 391 | @Override public void enterNumber(LuceneSqlParser.NumberContext ctx) { } 392 | /** 393 | * {@inheritDoc} 394 | * 395 | *

The default implementation does nothing.

396 | */ 397 | @Override public void exitNumber(LuceneSqlParser.NumberContext ctx) { } 398 | /** 399 | * {@inheritDoc} 400 | * 401 | *

The default implementation does nothing.

402 | */ 403 | @Override public void enterTerm(LuceneSqlParser.TermContext ctx) { } 404 | /** 405 | * {@inheritDoc} 406 | * 407 | *

The default implementation does nothing.

408 | */ 409 | @Override public void exitTerm(LuceneSqlParser.TermContext ctx) { } 410 | /** 411 | * {@inheritDoc} 412 | * 413 | *

The default implementation does nothing.

414 | */ 415 | @Override public void enterPhrase(LuceneSqlParser.PhraseContext ctx) { } 416 | /** 417 | * {@inheritDoc} 418 | * 419 | *

The default implementation does nothing.

420 | */ 421 | @Override public void exitPhrase(LuceneSqlParser.PhraseContext ctx) { } 422 | /** 423 | * {@inheritDoc} 424 | * 425 | *

The default implementation does nothing.

426 | */ 427 | @Override public void enterDate(LuceneSqlParser.DateContext ctx) { } 428 | /** 429 | * {@inheritDoc} 430 | * 431 | *

The default implementation does nothing.

432 | */ 433 | @Override public void exitDate(LuceneSqlParser.DateContext ctx) { } 434 | /** 435 | * {@inheritDoc} 436 | * 437 | *

The default implementation does nothing.

438 | */ 439 | @Override public void enterMULTI_PHRASE(LuceneSqlParser.MULTI_PHRASEContext ctx) { } 440 | /** 441 | * {@inheritDoc} 442 | * 443 | *

The default implementation does nothing.

444 | */ 445 | @Override public void exitMULTI_PHRASE(LuceneSqlParser.MULTI_PHRASEContext ctx) { } 446 | /** 447 | * {@inheritDoc} 448 | * 449 | *

The default implementation does nothing.

450 | */ 451 | @Override public void enterRegexp(LuceneSqlParser.RegexpContext ctx) { } 452 | /** 453 | * {@inheritDoc} 454 | * 455 | *

The default implementation does nothing.

456 | */ 457 | @Override public void exitRegexp(LuceneSqlParser.RegexpContext ctx) { } 458 | /** 459 | * {@inheritDoc} 460 | * 461 | *

The default implementation does nothing.

462 | */ 463 | @Override public void enterBetween(LuceneSqlParser.BetweenContext ctx) { } 464 | /** 465 | * {@inheritDoc} 466 | * 467 | *

The default implementation does nothing.

468 | */ 469 | @Override public void exitBetween(LuceneSqlParser.BetweenContext ctx) { } 470 | /** 471 | * {@inheritDoc} 472 | * 473 | *

The default implementation does nothing.

474 | */ 475 | @Override public void enterBetween_term(LuceneSqlParser.Between_termContext ctx) { } 476 | /** 477 | * {@inheritDoc} 478 | * 479 | *

The default implementation does nothing.

480 | */ 481 | @Override public void exitBetween_term(LuceneSqlParser.Between_termContext ctx) { } 482 | /** 483 | * {@inheritDoc} 484 | * 485 | *

The default implementation does nothing.

486 | */ 487 | @Override public void enterBetween_number(LuceneSqlParser.Between_numberContext ctx) { } 488 | /** 489 | * {@inheritDoc} 490 | * 491 | *

The default implementation does nothing.

492 | */ 493 | @Override public void exitBetween_number(LuceneSqlParser.Between_numberContext ctx) { } 494 | /** 495 | * {@inheritDoc} 496 | * 497 | *

The default implementation does nothing.

498 | */ 499 | @Override public void enterLike(LuceneSqlParser.LikeContext ctx) { } 500 | /** 501 | * {@inheritDoc} 502 | * 503 | *

The default implementation does nothing.

504 | */ 505 | @Override public void exitLike(LuceneSqlParser.LikeContext ctx) { } 506 | /** 507 | * {@inheritDoc} 508 | * 509 | *

The default implementation does nothing.

510 | */ 511 | @Override public void enterIn(LuceneSqlParser.InContext ctx) { } 512 | /** 513 | * {@inheritDoc} 514 | * 515 | *

The default implementation does nothing.

516 | */ 517 | @Override public void exitIn(LuceneSqlParser.InContext ctx) { } 518 | /** 519 | * {@inheritDoc} 520 | * 521 | *

The default implementation does nothing.

522 | */ 523 | @Override public void enterValue_list(LuceneSqlParser.Value_listContext ctx) { } 524 | /** 525 | * {@inheritDoc} 526 | * 527 | *

The default implementation does nothing.

528 | */ 529 | @Override public void exitValue_list(LuceneSqlParser.Value_listContext ctx) { } 530 | /** 531 | * {@inheritDoc} 532 | * 533 | *

The default implementation does nothing.

534 | */ 535 | @Override public void enterNumber_list(LuceneSqlParser.Number_listContext ctx) { } 536 | /** 537 | * {@inheritDoc} 538 | * 539 | *

The default implementation does nothing.

540 | */ 541 | @Override public void exitNumber_list(LuceneSqlParser.Number_listContext ctx) { } 542 | /** 543 | * {@inheritDoc} 544 | * 545 | *

The default implementation does nothing.

546 | */ 547 | @Override public void enterDate_list(LuceneSqlParser.Date_listContext ctx) { } 548 | /** 549 | * {@inheritDoc} 550 | * 551 | *

The default implementation does nothing.

552 | */ 553 | @Override public void exitDate_list(LuceneSqlParser.Date_listContext ctx) { } 554 | /** 555 | * {@inheritDoc} 556 | * 557 | *

The default implementation does nothing.

558 | */ 559 | @Override public void enterTerm_list(LuceneSqlParser.Term_listContext ctx) { } 560 | /** 561 | * {@inheritDoc} 562 | * 563 | *

The default implementation does nothing.

564 | */ 565 | @Override public void exitTerm_list(LuceneSqlParser.Term_listContext ctx) { } 566 | /** 567 | * {@inheritDoc} 568 | * 569 | *

The default implementation does nothing.

570 | */ 571 | @Override public void enterPhrase_list(LuceneSqlParser.Phrase_listContext ctx) { } 572 | /** 573 | * {@inheritDoc} 574 | * 575 | *

The default implementation does nothing.

576 | */ 577 | @Override public void exitPhrase_list(LuceneSqlParser.Phrase_listContext ctx) { } 578 | 579 | /** 580 | * {@inheritDoc} 581 | * 582 | *

The default implementation does nothing.

583 | */ 584 | @Override public void enterEveryRule(ParserRuleContext ctx) { } 585 | /** 586 | * {@inheritDoc} 587 | * 588 | *

The default implementation does nothing.

589 | */ 590 | @Override public void exitEveryRule(ParserRuleContext ctx) { } 591 | /** 592 | * {@inheritDoc} 593 | * 594 | *

The default implementation does nothing.

595 | */ 596 | @Override public void visitTerminal(TerminalNode node) { } 597 | /** 598 | * {@inheritDoc} 599 | * 600 | *

The default implementation does nothing.

601 | */ 602 | @Override public void visitErrorNode(ErrorNode node) { } 603 | } -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/generated/LuceneSqlBaseVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/bbejeck/dev/github_clones/sql-for-lucene/src/main/java/LuceneSql.g4 by ANTLR 4.5.1 2 | package bbejeck.sql.antlr.generated; 3 | import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; 4 | 5 | /** 6 | * This class provides an empty implementation of {@link LuceneSqlVisitor}, 7 | * which can be extended to create a visitor which only needs to handle a subset 8 | * of the available methods. 9 | * 10 | * @param The return type of the visit operation. Use {@link Void} for 11 | * operations with no return type. 12 | */ 13 | public class LuceneSqlBaseVisitor extends AbstractParseTreeVisitor implements LuceneSqlVisitor { 14 | /** 15 | * {@inheritDoc} 16 | * 17 | *

The default implementation returns the result of calling 18 | * {@link #visitChildren} on {@code ctx}.

19 | */ 20 | @Override public T visitQuery(LuceneSqlParser.QueryContext ctx) { return visitChildren(ctx); } 21 | /** 22 | * {@inheritDoc} 23 | * 24 | *

The default implementation returns the result of calling 25 | * {@link #visitChildren} on {@code ctx}.

26 | */ 27 | @Override public T visitSelect_stmt(LuceneSqlParser.Select_stmtContext ctx) { return visitChildren(ctx); } 28 | /** 29 | * {@inheritDoc} 30 | * 31 | *

The default implementation returns the result of calling 32 | * {@link #visitChildren} on {@code ctx}.

33 | */ 34 | @Override public T visitFrom_stmt(LuceneSqlParser.From_stmtContext ctx) { return visitChildren(ctx); } 35 | /** 36 | * {@inheritDoc} 37 | * 38 | *

The default implementation returns the result of calling 39 | * {@link #visitChildren} on {@code ctx}.

40 | */ 41 | @Override public T visitWhere_stmt(LuceneSqlParser.Where_stmtContext ctx) { return visitChildren(ctx); } 42 | /** 43 | * {@inheritDoc} 44 | * 45 | *

The default implementation returns the result of calling 46 | * {@link #visitChildren} on {@code ctx}.

47 | */ 48 | @Override public T visitLimit_stmt(LuceneSqlParser.Limit_stmtContext ctx) { return visitChildren(ctx); } 49 | /** 50 | * {@inheritDoc} 51 | * 52 | *

The default implementation returns the result of calling 53 | * {@link #visitChildren} on {@code ctx}.

54 | */ 55 | @Override public T visitSearch_condition(LuceneSqlParser.Search_conditionContext ctx) { return visitChildren(ctx); } 56 | /** 57 | * {@inheritDoc} 58 | * 59 | *

The default implementation returns the result of calling 60 | * {@link #visitChildren} on {@code ctx}.

61 | */ 62 | @Override public T visitPredicate(LuceneSqlParser.PredicateContext ctx) { return visitChildren(ctx); } 63 | /** 64 | * {@inheritDoc} 65 | * 66 | *

The default implementation returns the result of calling 67 | * {@link #visitChildren} on {@code ctx}.

68 | */ 69 | @Override public T visitComparison_predicate(LuceneSqlParser.Comparison_predicateContext ctx) { return visitChildren(ctx); } 70 | /** 71 | * {@inheritDoc} 72 | * 73 | *

The default implementation returns the result of calling 74 | * {@link #visitChildren} on {@code ctx}.

75 | */ 76 | @Override public T visitFunction_predicate(LuceneSqlParser.Function_predicateContext ctx) { return visitChildren(ctx); } 77 | /** 78 | * {@inheritDoc} 79 | * 80 | *

The default implementation returns the result of calling 81 | * {@link #visitChildren} on {@code ctx}.

82 | */ 83 | @Override public T visitField(LuceneSqlParser.FieldContext ctx) { return visitChildren(ctx); } 84 | /** 85 | * {@inheritDoc} 86 | * 87 | *

The default implementation returns the result of calling 88 | * {@link #visitChildren} on {@code ctx}.

89 | */ 90 | @Override public T visitEquals(LuceneSqlParser.EqualsContext ctx) { return visitChildren(ctx); } 91 | /** 92 | * {@inheritDoc} 93 | * 94 | *

The default implementation returns the result of calling 95 | * {@link #visitChildren} on {@code ctx}.

96 | */ 97 | @Override public T visitNotEqual(LuceneSqlParser.NotEqualContext ctx) { return visitChildren(ctx); } 98 | /** 99 | * {@inheritDoc} 100 | * 101 | *

The default implementation returns the result of calling 102 | * {@link #visitChildren} on {@code ctx}.

103 | */ 104 | @Override public T visitRange_op(LuceneSqlParser.Range_opContext ctx) { return visitChildren(ctx); } 105 | /** 106 | * {@inheritDoc} 107 | * 108 | *

The default implementation returns the result of calling 109 | * {@link #visitChildren} on {@code ctx}.

110 | */ 111 | @Override public T visitGreaterThanNumber(LuceneSqlParser.GreaterThanNumberContext ctx) { return visitChildren(ctx); } 112 | /** 113 | * {@inheritDoc} 114 | * 115 | *

The default implementation returns the result of calling 116 | * {@link #visitChildren} on {@code ctx}.

117 | */ 118 | @Override public T visitGreaterThanTerm(LuceneSqlParser.GreaterThanTermContext ctx) { return visitChildren(ctx); } 119 | /** 120 | * {@inheritDoc} 121 | * 122 | *

The default implementation returns the result of calling 123 | * {@link #visitChildren} on {@code ctx}.

124 | */ 125 | @Override public T visitGreaterThanDate(LuceneSqlParser.GreaterThanDateContext ctx) { return visitChildren(ctx); } 126 | /** 127 | * {@inheritDoc} 128 | * 129 | *

The default implementation returns the result of calling 130 | * {@link #visitChildren} on {@code ctx}.

131 | */ 132 | @Override public T visitGreaterThanEqNumber(LuceneSqlParser.GreaterThanEqNumberContext ctx) { return visitChildren(ctx); } 133 | /** 134 | * {@inheritDoc} 135 | * 136 | *

The default implementation returns the result of calling 137 | * {@link #visitChildren} on {@code ctx}.

138 | */ 139 | @Override public T visitGreaterThanEqTerm(LuceneSqlParser.GreaterThanEqTermContext ctx) { return visitChildren(ctx); } 140 | /** 141 | * {@inheritDoc} 142 | * 143 | *

The default implementation returns the result of calling 144 | * {@link #visitChildren} on {@code ctx}.

145 | */ 146 | @Override public T visitGreaterThanEqDate(LuceneSqlParser.GreaterThanEqDateContext ctx) { return visitChildren(ctx); } 147 | /** 148 | * {@inheritDoc} 149 | * 150 | *

The default implementation returns the result of calling 151 | * {@link #visitChildren} on {@code ctx}.

152 | */ 153 | @Override public T visitLessThanNumber(LuceneSqlParser.LessThanNumberContext ctx) { return visitChildren(ctx); } 154 | /** 155 | * {@inheritDoc} 156 | * 157 | *

The default implementation returns the result of calling 158 | * {@link #visitChildren} on {@code ctx}.

159 | */ 160 | @Override public T visitLessThanTerm(LuceneSqlParser.LessThanTermContext ctx) { return visitChildren(ctx); } 161 | /** 162 | * {@inheritDoc} 163 | * 164 | *

The default implementation returns the result of calling 165 | * {@link #visitChildren} on {@code ctx}.

166 | */ 167 | @Override public T visitLessThanDate(LuceneSqlParser.LessThanDateContext ctx) { return visitChildren(ctx); } 168 | /** 169 | * {@inheritDoc} 170 | * 171 | *

The default implementation returns the result of calling 172 | * {@link #visitChildren} on {@code ctx}.

173 | */ 174 | @Override public T visitLessThanEqNumber(LuceneSqlParser.LessThanEqNumberContext ctx) { return visitChildren(ctx); } 175 | /** 176 | * {@inheritDoc} 177 | * 178 | *

The default implementation returns the result of calling 179 | * {@link #visitChildren} on {@code ctx}.

180 | */ 181 | @Override public T visitLessThanEqTerm(LuceneSqlParser.LessThanEqTermContext ctx) { return visitChildren(ctx); } 182 | /** 183 | * {@inheritDoc} 184 | * 185 | *

The default implementation returns the result of calling 186 | * {@link #visitChildren} on {@code ctx}.

187 | */ 188 | @Override public T visitLessThanEqDate(LuceneSqlParser.LessThanEqDateContext ctx) { return visitChildren(ctx); } 189 | /** 190 | * {@inheritDoc} 191 | * 192 | *

The default implementation returns the result of calling 193 | * {@link #visitChildren} on {@code ctx}.

194 | */ 195 | @Override public T visitAnd(LuceneSqlParser.AndContext ctx) { return visitChildren(ctx); } 196 | /** 197 | * {@inheritDoc} 198 | * 199 | *

The default implementation returns the result of calling 200 | * {@link #visitChildren} on {@code ctx}.

201 | */ 202 | @Override public T visitOr(LuceneSqlParser.OrContext ctx) { return visitChildren(ctx); } 203 | /** 204 | * {@inheritDoc} 205 | * 206 | *

The default implementation returns the result of calling 207 | * {@link #visitChildren} on {@code ctx}.

208 | */ 209 | @Override public T visitNot(LuceneSqlParser.NotContext ctx) { return visitChildren(ctx); } 210 | /** 211 | * {@inheritDoc} 212 | * 213 | *

The default implementation returns the result of calling 214 | * {@link #visitChildren} on {@code ctx}.

215 | */ 216 | @Override public T visitAndNot(LuceneSqlParser.AndNotContext ctx) { return visitChildren(ctx); } 217 | /** 218 | * {@inheritDoc} 219 | * 220 | *

The default implementation returns the result of calling 221 | * {@link #visitChildren} on {@code ctx}.

222 | */ 223 | @Override public T visitOrNot(LuceneSqlParser.OrNotContext ctx) { return visitChildren(ctx); } 224 | /** 225 | * {@inheritDoc} 226 | * 227 | *

The default implementation returns the result of calling 228 | * {@link #visitChildren} on {@code ctx}.

229 | */ 230 | @Override public T visitNested_predicate(LuceneSqlParser.Nested_predicateContext ctx) { return visitChildren(ctx); } 231 | /** 232 | * {@inheritDoc} 233 | * 234 | *

The default implementation returns the result of calling 235 | * {@link #visitChildren} on {@code ctx}.

236 | */ 237 | @Override public T visitNumber(LuceneSqlParser.NumberContext ctx) { return visitChildren(ctx); } 238 | /** 239 | * {@inheritDoc} 240 | * 241 | *

The default implementation returns the result of calling 242 | * {@link #visitChildren} on {@code ctx}.

243 | */ 244 | @Override public T visitTerm(LuceneSqlParser.TermContext ctx) { return visitChildren(ctx); } 245 | /** 246 | * {@inheritDoc} 247 | * 248 | *

The default implementation returns the result of calling 249 | * {@link #visitChildren} on {@code ctx}.

250 | */ 251 | @Override public T visitPhrase(LuceneSqlParser.PhraseContext ctx) { return visitChildren(ctx); } 252 | /** 253 | * {@inheritDoc} 254 | * 255 | *

The default implementation returns the result of calling 256 | * {@link #visitChildren} on {@code ctx}.

257 | */ 258 | @Override public T visitDate(LuceneSqlParser.DateContext ctx) { return visitChildren(ctx); } 259 | /** 260 | * {@inheritDoc} 261 | * 262 | *

The default implementation returns the result of calling 263 | * {@link #visitChildren} on {@code ctx}.

264 | */ 265 | @Override public T visitMULTI_PHRASE(LuceneSqlParser.MULTI_PHRASEContext ctx) { return visitChildren(ctx); } 266 | /** 267 | * {@inheritDoc} 268 | * 269 | *

The default implementation returns the result of calling 270 | * {@link #visitChildren} on {@code ctx}.

271 | */ 272 | @Override public T visitRegexp(LuceneSqlParser.RegexpContext ctx) { return visitChildren(ctx); } 273 | /** 274 | * {@inheritDoc} 275 | * 276 | *

The default implementation returns the result of calling 277 | * {@link #visitChildren} on {@code ctx}.

278 | */ 279 | @Override public T visitBetween(LuceneSqlParser.BetweenContext ctx) { return visitChildren(ctx); } 280 | /** 281 | * {@inheritDoc} 282 | * 283 | *

The default implementation returns the result of calling 284 | * {@link #visitChildren} on {@code ctx}.

285 | */ 286 | @Override public T visitBetween_term(LuceneSqlParser.Between_termContext ctx) { return visitChildren(ctx); } 287 | /** 288 | * {@inheritDoc} 289 | * 290 | *

The default implementation returns the result of calling 291 | * {@link #visitChildren} on {@code ctx}.

292 | */ 293 | @Override public T visitBetween_number(LuceneSqlParser.Between_numberContext ctx) { return visitChildren(ctx); } 294 | /** 295 | * {@inheritDoc} 296 | * 297 | *

The default implementation returns the result of calling 298 | * {@link #visitChildren} on {@code ctx}.

299 | */ 300 | @Override public T visitLike(LuceneSqlParser.LikeContext ctx) { return visitChildren(ctx); } 301 | /** 302 | * {@inheritDoc} 303 | * 304 | *

The default implementation returns the result of calling 305 | * {@link #visitChildren} on {@code ctx}.

306 | */ 307 | @Override public T visitIn(LuceneSqlParser.InContext ctx) { return visitChildren(ctx); } 308 | /** 309 | * {@inheritDoc} 310 | * 311 | *

The default implementation returns the result of calling 312 | * {@link #visitChildren} on {@code ctx}.

313 | */ 314 | @Override public T visitValue_list(LuceneSqlParser.Value_listContext ctx) { return visitChildren(ctx); } 315 | /** 316 | * {@inheritDoc} 317 | * 318 | *

The default implementation returns the result of calling 319 | * {@link #visitChildren} on {@code ctx}.

320 | */ 321 | @Override public T visitNumber_list(LuceneSqlParser.Number_listContext ctx) { return visitChildren(ctx); } 322 | /** 323 | * {@inheritDoc} 324 | * 325 | *

The default implementation returns the result of calling 326 | * {@link #visitChildren} on {@code ctx}.

327 | */ 328 | @Override public T visitDate_list(LuceneSqlParser.Date_listContext ctx) { return visitChildren(ctx); } 329 | /** 330 | * {@inheritDoc} 331 | * 332 | *

The default implementation returns the result of calling 333 | * {@link #visitChildren} on {@code ctx}.

334 | */ 335 | @Override public T visitTerm_list(LuceneSqlParser.Term_listContext ctx) { return visitChildren(ctx); } 336 | /** 337 | * {@inheritDoc} 338 | * 339 | *

The default implementation returns the result of calling 340 | * {@link #visitChildren} on {@code ctx}.

341 | */ 342 | @Override public T visitPhrase_list(LuceneSqlParser.Phrase_listContext ctx) { return visitChildren(ctx); } 343 | } -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/generated/LuceneSqlLexer.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/bbejeck/dev/github_clones/sql-for-lucene/src/main/java/LuceneSql.g4 by ANTLR 4.5.1 2 | package bbejeck.sql.antlr.generated; 3 | import org.antlr.v4.runtime.Lexer; 4 | import org.antlr.v4.runtime.CharStream; 5 | import org.antlr.v4.runtime.Token; 6 | import org.antlr.v4.runtime.TokenStream; 7 | import org.antlr.v4.runtime.*; 8 | import org.antlr.v4.runtime.atn.*; 9 | import org.antlr.v4.runtime.dfa.DFA; 10 | import org.antlr.v4.runtime.misc.*; 11 | 12 | @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) 13 | public class LuceneSqlLexer extends Lexer { 14 | static { RuntimeMetaData.checkVersion("4.5.1", RuntimeMetaData.VERSION); } 15 | 16 | protected static final DFA[] _decisionToDFA; 17 | protected static final PredictionContextCache _sharedContextCache = 18 | new PredictionContextCache(); 19 | public static final int 20 | SELECT=1, FROM=2, WHERE=3, AND=4, OR=5, NOT=6, DESCRIBE=7, MATCHES=8, 21 | BETWEEN=9, LIKE=10, LIMIT=11, EQ=12, NE=13, GT=14, LT=15, GTE=16, LTE=17, 22 | IN=18, SPLAT=19, NUMBER=20, DATE=21, FIELD=22, PATH=23, TERM=24, PHRASE=25, 23 | WILD_CARD=26, MULTI_PHRASE=27, DB_QUOTE_STRING_LIT=28, COMMA=29, LPAREN=30, 24 | RPAREN=31, WS=32; 25 | public static String[] modeNames = { 26 | "DEFAULT_MODE" 27 | }; 28 | 29 | public static final String[] ruleNames = { 30 | "SELECT", "FROM", "WHERE", "AND", "OR", "NOT", "DESCRIBE", "MATCHES", 31 | "BETWEEN", "LIKE", "LIMIT", "EQ", "NE", "GT", "LT", "GTE", "LTE", "IN", 32 | "SPLAT", "DIGIT", "NUMBER", "DATE_SEP", "DATE", "FIELD", "PATH", "TERM", 33 | "PHRASE", "WILD_CARD", "MULTI_PHRASE", "DB_QUOTE_STRING_LIT", "COMMA", 34 | "LPAREN", "RPAREN", "WS" 35 | }; 36 | 37 | private static final String[] _LITERAL_NAMES = { 38 | null, null, null, null, null, null, null, null, null, null, null, null, 39 | "'='", "'!='", "'>'", "'<'", "'>='", "'<='", null, "'*'", null, null, 40 | null, null, null, null, null, null, null, "','", "'('", "')'" 41 | }; 42 | private static final String[] _SYMBOLIC_NAMES = { 43 | null, "SELECT", "FROM", "WHERE", "AND", "OR", "NOT", "DESCRIBE", "MATCHES", 44 | "BETWEEN", "LIKE", "LIMIT", "EQ", "NE", "GT", "LT", "GTE", "LTE", "IN", 45 | "SPLAT", "NUMBER", "DATE", "FIELD", "PATH", "TERM", "PHRASE", "WILD_CARD", 46 | "MULTI_PHRASE", "DB_QUOTE_STRING_LIT", "COMMA", "LPAREN", "RPAREN", "WS" 47 | }; 48 | public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); 49 | 50 | /** 51 | * @deprecated Use {@link #VOCABULARY} instead. 52 | */ 53 | @Deprecated 54 | public static final String[] tokenNames; 55 | static { 56 | tokenNames = new String[_SYMBOLIC_NAMES.length]; 57 | for (int i = 0; i < tokenNames.length; i++) { 58 | tokenNames[i] = VOCABULARY.getLiteralName(i); 59 | if (tokenNames[i] == null) { 60 | tokenNames[i] = VOCABULARY.getSymbolicName(i); 61 | } 62 | 63 | if (tokenNames[i] == null) { 64 | tokenNames[i] = ""; 65 | } 66 | } 67 | } 68 | 69 | @Override 70 | @Deprecated 71 | public String[] getTokenNames() { 72 | return tokenNames; 73 | } 74 | 75 | @Override 76 | 77 | public Vocabulary getVocabulary() { 78 | return VOCABULARY; 79 | } 80 | 81 | 82 | public LuceneSqlLexer(CharStream input) { 83 | super(input); 84 | _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); 85 | } 86 | 87 | @Override 88 | public String getGrammarFileName() { return "LuceneSql.g4"; } 89 | 90 | @Override 91 | public String[] getRuleNames() { return ruleNames; } 92 | 93 | @Override 94 | public String getSerializedATN() { return _serializedATN; } 95 | 96 | @Override 97 | public String[] getModeNames() { return modeNames; } 98 | 99 | @Override 100 | public ATN getATN() { return _ATN; } 101 | 102 | public static final String _serializedATN = 103 | "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\"\u011c\b\1\4\2\t"+ 104 | "\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+ 105 | "\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ 106 | "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ 107 | "\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+ 108 | "\t!\4\"\t\"\4#\t#\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\4"+ 109 | "\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\b\3"+ 110 | "\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n"+ 111 | "\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f"+ 112 | "\3\f\3\r\3\r\3\16\3\16\3\16\3\17\3\17\3\20\3\20\3\21\3\21\3\21\3\22\3"+ 113 | "\22\3\22\3\23\3\23\3\23\3\24\3\24\3\25\3\25\3\26\3\26\7\26\u00a1\n\26"+ 114 | "\f\26\16\26\u00a4\13\26\3\27\3\27\3\30\6\30\u00a9\n\30\r\30\16\30\u00aa"+ 115 | "\3\30\5\30\u00ae\n\30\6\30\u00b0\n\30\r\30\16\30\u00b1\3\31\6\31\u00b5"+ 116 | "\n\31\r\31\16\31\u00b6\3\31\3\31\7\31\u00bb\n\31\f\31\16\31\u00be\13\31"+ 117 | "\3\31\7\31\u00c1\n\31\f\31\16\31\u00c4\13\31\7\31\u00c6\n\31\f\31\16\31"+ 118 | "\u00c9\13\31\3\32\3\32\3\32\5\32\u00ce\n\32\3\32\5\32\u00d1\n\32\3\32"+ 119 | "\6\32\u00d4\n\32\r\32\16\32\u00d5\3\32\6\32\u00d9\n\32\r\32\16\32\u00da"+ 120 | "\3\32\3\32\3\33\3\33\7\33\u00e1\n\33\f\33\16\33\u00e4\13\33\3\33\3\33"+ 121 | "\3\34\3\34\7\34\u00ea\n\34\f\34\16\34\u00ed\13\34\3\34\3\34\3\35\3\35"+ 122 | "\7\35\u00f3\n\35\f\35\16\35\u00f6\13\35\3\35\3\35\3\36\3\36\6\36\u00fc"+ 123 | "\n\36\r\36\16\36\u00fd\3\36\6\36\u0101\n\36\r\36\16\36\u0102\3\36\3\36"+ 124 | "\3\37\3\37\7\37\u0109\n\37\f\37\16\37\u010c\13\37\3\37\3\37\3 \3 \3!\3"+ 125 | "!\3\"\3\"\3#\6#\u0117\n#\r#\16#\u0118\3#\3#\2\2$\3\3\5\4\7\5\t\6\13\7"+ 126 | "\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25"+ 127 | ")\2+\26-\2/\27\61\30\63\31\65\32\67\339\34;\35=\36?\37A C!E\"\3\2\36\4"+ 128 | "\2UUuu\4\2GGgg\4\2NNnn\4\2EEee\4\2VVvv\4\2HHhh\4\2TTtt\4\2QQqq\4\2OOo"+ 129 | "o\4\2YYyy\4\2JJjj\4\2CCcc\4\2PPpp\4\2FFff\4\2KKkk\4\2DDdd\4\2MMmm\3\2"+ 130 | "\62;\4\2//\61\61\4\2C\\c|\4\2<\2\2\u0090 \3\2\2\2\u0091\u0092\7@\2\2\u0092\u0093\7?\2\2\u0093"+ 158 | "\"\3\2\2\2\u0094\u0095\7>\2\2\u0095\u0096\7?\2\2\u0096$\3\2\2\2\u0097"+ 159 | "\u0098\t\20\2\2\u0098\u0099\t\16\2\2\u0099&\3\2\2\2\u009a\u009b\7,\2\2"+ 160 | "\u009b(\3\2\2\2\u009c\u009d\t\23\2\2\u009d*\3\2\2\2\u009e\u00a2\5)\25"+ 161 | "\2\u009f\u00a1\5)\25\2\u00a0\u009f\3\2\2\2\u00a1\u00a4\3\2\2\2\u00a2\u00a0"+ 162 | "\3\2\2\2\u00a2\u00a3\3\2\2\2\u00a3,\3\2\2\2\u00a4\u00a2\3\2\2\2\u00a5"+ 163 | "\u00a6\t\24\2\2\u00a6.\3\2\2\2\u00a7\u00a9\5+\26\2\u00a8\u00a7\3\2\2\2"+ 164 | "\u00a9\u00aa\3\2\2\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab\u00ad"+ 165 | "\3\2\2\2\u00ac\u00ae\5-\27\2\u00ad\u00ac\3\2\2\2\u00ad\u00ae\3\2\2\2\u00ae"+ 166 | "\u00b0\3\2\2\2\u00af\u00a8\3\2\2\2\u00b0\u00b1\3\2\2\2\u00b1\u00af\3\2"+ 167 | "\2\2\u00b1\u00b2\3\2\2\2\u00b2\60\3\2\2\2\u00b3\u00b5\t\25\2\2\u00b4\u00b3"+ 168 | "\3\2\2\2\u00b5\u00b6\3\2\2\2\u00b6\u00b4\3\2\2\2\u00b6\u00b7\3\2\2\2\u00b7"+ 169 | "\u00c7\3\2\2\2\u00b8\u00bc\t\26\2\2\u00b9\u00bb\t\23\2\2\u00ba\u00b9\3"+ 170 | "\2\2\2\u00bb\u00be\3\2\2\2\u00bc\u00ba\3\2\2\2\u00bc\u00bd\3\2\2\2\u00bd"+ 171 | "\u00c2\3\2\2\2\u00be\u00bc\3\2\2\2\u00bf\u00c1\t\25\2\2\u00c0\u00bf\3"+ 172 | "\2\2\2\u00c1\u00c4\3\2\2\2\u00c2\u00c0\3\2\2\2\u00c2\u00c3\3\2\2\2\u00c3"+ 173 | "\u00c6\3\2\2\2\u00c4\u00c2\3\2\2\2\u00c5\u00b8\3\2\2\2\u00c6\u00c9\3\2"+ 174 | "\2\2\u00c7\u00c5\3\2\2\2\u00c7\u00c8\3\2\2\2\u00c8\62\3\2\2\2\u00c9\u00c7"+ 175 | "\3\2\2\2\u00ca\u00cd\7)\2\2\u00cb\u00cc\t\25\2\2\u00cc\u00ce\7<\2\2\u00cd"+ 176 | "\u00cb\3\2\2\2\u00cd\u00ce\3\2\2\2\u00ce\u00d0\3\2\2\2\u00cf\u00d1\7\61"+ 177 | "\2\2\u00d0\u00cf\3\2\2\2\u00d0\u00d1\3\2\2\2\u00d1\u00d8\3\2\2\2\u00d2"+ 178 | "\u00d4\n\27\2\2\u00d3\u00d2\3\2\2\2\u00d4\u00d5\3\2\2\2\u00d5\u00d3\3"+ 179 | "\2\2\2\u00d5\u00d6\3\2\2\2\u00d6\u00d7\3\2\2\2\u00d7\u00d9\7\61\2\2\u00d8"+ 180 | "\u00d3\3\2\2\2\u00d9\u00da\3\2\2\2\u00da\u00d8\3\2\2\2\u00da\u00db\3\2"+ 181 | "\2\2\u00db\u00dc\3\2\2\2\u00dc\u00dd\7)\2\2\u00dd\64\3\2\2\2\u00de\u00e2"+ 182 | "\7)\2\2\u00df\u00e1\n\30\2\2\u00e0\u00df\3\2\2\2\u00e1\u00e4\3\2\2\2\u00e2"+ 183 | "\u00e0\3\2\2\2\u00e2\u00e3\3\2\2\2\u00e3\u00e5\3\2\2\2\u00e4\u00e2\3\2"+ 184 | "\2\2\u00e5\u00e6\7)\2\2\u00e6\66\3\2\2\2\u00e7\u00eb\7)\2\2\u00e8\u00ea"+ 185 | "\n\31\2\2\u00e9\u00e8\3\2\2\2\u00ea\u00ed\3\2\2\2\u00eb\u00e9\3\2\2\2"+ 186 | "\u00eb\u00ec\3\2\2\2\u00ec\u00ee\3\2\2\2\u00ed\u00eb\3\2\2\2\u00ee\u00ef"+ 187 | "\7)\2\2\u00ef8\3\2\2\2\u00f0\u00f4\7)\2\2\u00f1\u00f3\n\32\2\2\u00f2\u00f1"+ 188 | "\3\2\2\2\u00f3\u00f6\3\2\2\2\u00f4\u00f2\3\2\2\2\u00f4\u00f5\3\2\2\2\u00f5"+ 189 | "\u00f7\3\2\2\2\u00f6\u00f4\3\2\2\2\u00f7\u00f8\7)\2\2\u00f8:\3\2\2\2\u00f9"+ 190 | "\u00fb\7)\2\2\u00fa\u00fc\n\30\2\2\u00fb\u00fa\3\2\2\2\u00fc\u00fd\3\2"+ 191 | "\2\2\u00fd\u00fb\3\2\2\2\u00fd\u00fe\3\2\2\2\u00fe\u0100\3\2\2\2\u00ff"+ 192 | "\u0101\n\33\2\2\u0100\u00ff\3\2\2\2\u0101\u0102\3\2\2\2\u0102\u0100\3"+ 193 | "\2\2\2\u0102\u0103\3\2\2\2\u0103\u0104\3\2\2\2\u0104\u0105\7)\2\2\u0105"+ 194 | "<\3\2\2\2\u0106\u010a\7$\2\2\u0107\u0109\n\34\2\2\u0108\u0107\3\2\2\2"+ 195 | "\u0109\u010c\3\2\2\2\u010a\u0108\3\2\2\2\u010a\u010b\3\2\2\2\u010b\u010d"+ 196 | "\3\2\2\2\u010c\u010a\3\2\2\2\u010d\u010e\7$\2\2\u010e>\3\2\2\2\u010f\u0110"+ 197 | "\7.\2\2\u0110@\3\2\2\2\u0111\u0112\7*\2\2\u0112B\3\2\2\2\u0113\u0114\7"+ 198 | "+\2\2\u0114D\3\2\2\2\u0115\u0117\t\35\2\2\u0116\u0115\3\2\2\2\u0117\u0118"+ 199 | "\3\2\2\2\u0118\u0116\3\2\2\2\u0118\u0119\3\2\2\2\u0119\u011a\3\2\2\2\u011a"+ 200 | "\u011b\b#\2\2\u011bF\3\2\2\2\26\2\u00a2\u00aa\u00ad\u00b1\u00b6\u00bc"+ 201 | "\u00c2\u00c7\u00cd\u00d0\u00d5\u00da\u00e2\u00eb\u00f4\u00fd\u0102\u010a"+ 202 | "\u0118\3\b\2\2"; 203 | public static final ATN _ATN = 204 | new ATNDeserializer().deserialize(_serializedATN.toCharArray()); 205 | static { 206 | _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; 207 | for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { 208 | _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); 209 | } 210 | } 211 | } -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/generated/LuceneSqlLexer.tokens: -------------------------------------------------------------------------------- 1 | SELECT=1 2 | FROM=2 3 | WHERE=3 4 | AND=4 5 | OR=5 6 | NOT=6 7 | DESCRIBE=7 8 | MATCHES=8 9 | BETWEEN=9 10 | LIKE=10 11 | LIMIT=11 12 | EQ=12 13 | NE=13 14 | GT=14 15 | LT=15 16 | GTE=16 17 | LTE=17 18 | IN=18 19 | SPLAT=19 20 | NUMBER=20 21 | DATE=21 22 | FIELD=22 23 | PATH=23 24 | TERM=24 25 | PHRASE=25 26 | WILD_CARD=26 27 | MULTI_PHRASE=27 28 | DB_QUOTE_STRING_LIT=28 29 | COMMA=29 30 | LPAREN=30 31 | RPAREN=31 32 | WS=32 33 | '='=12 34 | '!='=13 35 | '>'=14 36 | '<'=15 37 | '>='=16 38 | '<='=17 39 | '*'=19 40 | ','=29 41 | '('=30 42 | ')'=31 43 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/generated/LuceneSqlListener.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/bbejeck/dev/github_clones/sql-for-lucene/src/main/java/LuceneSql.g4 by ANTLR 4.5.1 2 | package bbejeck.sql.antlr.generated; 3 | import org.antlr.v4.runtime.tree.ParseTreeListener; 4 | 5 | /** 6 | * This interface defines a complete listener for a parse tree produced by 7 | * {@link LuceneSqlParser}. 8 | */ 9 | public interface LuceneSqlListener extends ParseTreeListener { 10 | /** 11 | * Enter a parse tree produced by {@link LuceneSqlParser#query}. 12 | * @param ctx the parse tree 13 | */ 14 | void enterQuery(LuceneSqlParser.QueryContext ctx); 15 | /** 16 | * Exit a parse tree produced by {@link LuceneSqlParser#query}. 17 | * @param ctx the parse tree 18 | */ 19 | void exitQuery(LuceneSqlParser.QueryContext ctx); 20 | /** 21 | * Enter a parse tree produced by {@link LuceneSqlParser#select_stmt}. 22 | * @param ctx the parse tree 23 | */ 24 | void enterSelect_stmt(LuceneSqlParser.Select_stmtContext ctx); 25 | /** 26 | * Exit a parse tree produced by {@link LuceneSqlParser#select_stmt}. 27 | * @param ctx the parse tree 28 | */ 29 | void exitSelect_stmt(LuceneSqlParser.Select_stmtContext ctx); 30 | /** 31 | * Enter a parse tree produced by {@link LuceneSqlParser#from_stmt}. 32 | * @param ctx the parse tree 33 | */ 34 | void enterFrom_stmt(LuceneSqlParser.From_stmtContext ctx); 35 | /** 36 | * Exit a parse tree produced by {@link LuceneSqlParser#from_stmt}. 37 | * @param ctx the parse tree 38 | */ 39 | void exitFrom_stmt(LuceneSqlParser.From_stmtContext ctx); 40 | /** 41 | * Enter a parse tree produced by {@link LuceneSqlParser#where_stmt}. 42 | * @param ctx the parse tree 43 | */ 44 | void enterWhere_stmt(LuceneSqlParser.Where_stmtContext ctx); 45 | /** 46 | * Exit a parse tree produced by {@link LuceneSqlParser#where_stmt}. 47 | * @param ctx the parse tree 48 | */ 49 | void exitWhere_stmt(LuceneSqlParser.Where_stmtContext ctx); 50 | /** 51 | * Enter a parse tree produced by {@link LuceneSqlParser#limit_stmt}. 52 | * @param ctx the parse tree 53 | */ 54 | void enterLimit_stmt(LuceneSqlParser.Limit_stmtContext ctx); 55 | /** 56 | * Exit a parse tree produced by {@link LuceneSqlParser#limit_stmt}. 57 | * @param ctx the parse tree 58 | */ 59 | void exitLimit_stmt(LuceneSqlParser.Limit_stmtContext ctx); 60 | /** 61 | * Enter a parse tree produced by {@link LuceneSqlParser#search_condition}. 62 | * @param ctx the parse tree 63 | */ 64 | void enterSearch_condition(LuceneSqlParser.Search_conditionContext ctx); 65 | /** 66 | * Exit a parse tree produced by {@link LuceneSqlParser#search_condition}. 67 | * @param ctx the parse tree 68 | */ 69 | void exitSearch_condition(LuceneSqlParser.Search_conditionContext ctx); 70 | /** 71 | * Enter a parse tree produced by {@link LuceneSqlParser#predicate}. 72 | * @param ctx the parse tree 73 | */ 74 | void enterPredicate(LuceneSqlParser.PredicateContext ctx); 75 | /** 76 | * Exit a parse tree produced by {@link LuceneSqlParser#predicate}. 77 | * @param ctx the parse tree 78 | */ 79 | void exitPredicate(LuceneSqlParser.PredicateContext ctx); 80 | /** 81 | * Enter a parse tree produced by {@link LuceneSqlParser#comparison_predicate}. 82 | * @param ctx the parse tree 83 | */ 84 | void enterComparison_predicate(LuceneSqlParser.Comparison_predicateContext ctx); 85 | /** 86 | * Exit a parse tree produced by {@link LuceneSqlParser#comparison_predicate}. 87 | * @param ctx the parse tree 88 | */ 89 | void exitComparison_predicate(LuceneSqlParser.Comparison_predicateContext ctx); 90 | /** 91 | * Enter a parse tree produced by {@link LuceneSqlParser#function_predicate}. 92 | * @param ctx the parse tree 93 | */ 94 | void enterFunction_predicate(LuceneSqlParser.Function_predicateContext ctx); 95 | /** 96 | * Exit a parse tree produced by {@link LuceneSqlParser#function_predicate}. 97 | * @param ctx the parse tree 98 | */ 99 | void exitFunction_predicate(LuceneSqlParser.Function_predicateContext ctx); 100 | /** 101 | * Enter a parse tree produced by {@link LuceneSqlParser#field}. 102 | * @param ctx the parse tree 103 | */ 104 | void enterField(LuceneSqlParser.FieldContext ctx); 105 | /** 106 | * Exit a parse tree produced by {@link LuceneSqlParser#field}. 107 | * @param ctx the parse tree 108 | */ 109 | void exitField(LuceneSqlParser.FieldContext ctx); 110 | /** 111 | * Enter a parse tree produced by the {@code Equals} 112 | * labeled alternative in {@link LuceneSqlParser#comparison_op}. 113 | * @param ctx the parse tree 114 | */ 115 | void enterEquals(LuceneSqlParser.EqualsContext ctx); 116 | /** 117 | * Exit a parse tree produced by the {@code Equals} 118 | * labeled alternative in {@link LuceneSqlParser#comparison_op}. 119 | * @param ctx the parse tree 120 | */ 121 | void exitEquals(LuceneSqlParser.EqualsContext ctx); 122 | /** 123 | * Enter a parse tree produced by the {@code NotEqual} 124 | * labeled alternative in {@link LuceneSqlParser#comparison_op}. 125 | * @param ctx the parse tree 126 | */ 127 | void enterNotEqual(LuceneSqlParser.NotEqualContext ctx); 128 | /** 129 | * Exit a parse tree produced by the {@code NotEqual} 130 | * labeled alternative in {@link LuceneSqlParser#comparison_op}. 131 | * @param ctx the parse tree 132 | */ 133 | void exitNotEqual(LuceneSqlParser.NotEqualContext ctx); 134 | /** 135 | * Enter a parse tree produced by {@link LuceneSqlParser#range_op}. 136 | * @param ctx the parse tree 137 | */ 138 | void enterRange_op(LuceneSqlParser.Range_opContext ctx); 139 | /** 140 | * Exit a parse tree produced by {@link LuceneSqlParser#range_op}. 141 | * @param ctx the parse tree 142 | */ 143 | void exitRange_op(LuceneSqlParser.Range_opContext ctx); 144 | /** 145 | * Enter a parse tree produced by the {@code greaterThanNumber} 146 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 147 | * @param ctx the parse tree 148 | */ 149 | void enterGreaterThanNumber(LuceneSqlParser.GreaterThanNumberContext ctx); 150 | /** 151 | * Exit a parse tree produced by the {@code greaterThanNumber} 152 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 153 | * @param ctx the parse tree 154 | */ 155 | void exitGreaterThanNumber(LuceneSqlParser.GreaterThanNumberContext ctx); 156 | /** 157 | * Enter a parse tree produced by the {@code greaterThanTerm} 158 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 159 | * @param ctx the parse tree 160 | */ 161 | void enterGreaterThanTerm(LuceneSqlParser.GreaterThanTermContext ctx); 162 | /** 163 | * Exit a parse tree produced by the {@code greaterThanTerm} 164 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 165 | * @param ctx the parse tree 166 | */ 167 | void exitGreaterThanTerm(LuceneSqlParser.GreaterThanTermContext ctx); 168 | /** 169 | * Enter a parse tree produced by the {@code greaterThanDate} 170 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 171 | * @param ctx the parse tree 172 | */ 173 | void enterGreaterThanDate(LuceneSqlParser.GreaterThanDateContext ctx); 174 | /** 175 | * Exit a parse tree produced by the {@code greaterThanDate} 176 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 177 | * @param ctx the parse tree 178 | */ 179 | void exitGreaterThanDate(LuceneSqlParser.GreaterThanDateContext ctx); 180 | /** 181 | * Enter a parse tree produced by the {@code greaterThanEqNumber} 182 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 183 | * @param ctx the parse tree 184 | */ 185 | void enterGreaterThanEqNumber(LuceneSqlParser.GreaterThanEqNumberContext ctx); 186 | /** 187 | * Exit a parse tree produced by the {@code greaterThanEqNumber} 188 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 189 | * @param ctx the parse tree 190 | */ 191 | void exitGreaterThanEqNumber(LuceneSqlParser.GreaterThanEqNumberContext ctx); 192 | /** 193 | * Enter a parse tree produced by the {@code greaterThanEqTerm} 194 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 195 | * @param ctx the parse tree 196 | */ 197 | void enterGreaterThanEqTerm(LuceneSqlParser.GreaterThanEqTermContext ctx); 198 | /** 199 | * Exit a parse tree produced by the {@code greaterThanEqTerm} 200 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 201 | * @param ctx the parse tree 202 | */ 203 | void exitGreaterThanEqTerm(LuceneSqlParser.GreaterThanEqTermContext ctx); 204 | /** 205 | * Enter a parse tree produced by the {@code greaterThanEqDate} 206 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 207 | * @param ctx the parse tree 208 | */ 209 | void enterGreaterThanEqDate(LuceneSqlParser.GreaterThanEqDateContext ctx); 210 | /** 211 | * Exit a parse tree produced by the {@code greaterThanEqDate} 212 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 213 | * @param ctx the parse tree 214 | */ 215 | void exitGreaterThanEqDate(LuceneSqlParser.GreaterThanEqDateContext ctx); 216 | /** 217 | * Enter a parse tree produced by the {@code lessThanNumber} 218 | * labeled alternative in {@link LuceneSqlParser#less_than}. 219 | * @param ctx the parse tree 220 | */ 221 | void enterLessThanNumber(LuceneSqlParser.LessThanNumberContext ctx); 222 | /** 223 | * Exit a parse tree produced by the {@code lessThanNumber} 224 | * labeled alternative in {@link LuceneSqlParser#less_than}. 225 | * @param ctx the parse tree 226 | */ 227 | void exitLessThanNumber(LuceneSqlParser.LessThanNumberContext ctx); 228 | /** 229 | * Enter a parse tree produced by the {@code lessThanTerm} 230 | * labeled alternative in {@link LuceneSqlParser#less_than}. 231 | * @param ctx the parse tree 232 | */ 233 | void enterLessThanTerm(LuceneSqlParser.LessThanTermContext ctx); 234 | /** 235 | * Exit a parse tree produced by the {@code lessThanTerm} 236 | * labeled alternative in {@link LuceneSqlParser#less_than}. 237 | * @param ctx the parse tree 238 | */ 239 | void exitLessThanTerm(LuceneSqlParser.LessThanTermContext ctx); 240 | /** 241 | * Enter a parse tree produced by the {@code lessThanDate} 242 | * labeled alternative in {@link LuceneSqlParser#less_than}. 243 | * @param ctx the parse tree 244 | */ 245 | void enterLessThanDate(LuceneSqlParser.LessThanDateContext ctx); 246 | /** 247 | * Exit a parse tree produced by the {@code lessThanDate} 248 | * labeled alternative in {@link LuceneSqlParser#less_than}. 249 | * @param ctx the parse tree 250 | */ 251 | void exitLessThanDate(LuceneSqlParser.LessThanDateContext ctx); 252 | /** 253 | * Enter a parse tree produced by the {@code lessThanEqNumber} 254 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 255 | * @param ctx the parse tree 256 | */ 257 | void enterLessThanEqNumber(LuceneSqlParser.LessThanEqNumberContext ctx); 258 | /** 259 | * Exit a parse tree produced by the {@code lessThanEqNumber} 260 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 261 | * @param ctx the parse tree 262 | */ 263 | void exitLessThanEqNumber(LuceneSqlParser.LessThanEqNumberContext ctx); 264 | /** 265 | * Enter a parse tree produced by the {@code lessThanEqTerm} 266 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 267 | * @param ctx the parse tree 268 | */ 269 | void enterLessThanEqTerm(LuceneSqlParser.LessThanEqTermContext ctx); 270 | /** 271 | * Exit a parse tree produced by the {@code lessThanEqTerm} 272 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 273 | * @param ctx the parse tree 274 | */ 275 | void exitLessThanEqTerm(LuceneSqlParser.LessThanEqTermContext ctx); 276 | /** 277 | * Enter a parse tree produced by the {@code lessThanEqDate} 278 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 279 | * @param ctx the parse tree 280 | */ 281 | void enterLessThanEqDate(LuceneSqlParser.LessThanEqDateContext ctx); 282 | /** 283 | * Exit a parse tree produced by the {@code lessThanEqDate} 284 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 285 | * @param ctx the parse tree 286 | */ 287 | void exitLessThanEqDate(LuceneSqlParser.LessThanEqDateContext ctx); 288 | /** 289 | * Enter a parse tree produced by the {@code And} 290 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 291 | * @param ctx the parse tree 292 | */ 293 | void enterAnd(LuceneSqlParser.AndContext ctx); 294 | /** 295 | * Exit a parse tree produced by the {@code And} 296 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 297 | * @param ctx the parse tree 298 | */ 299 | void exitAnd(LuceneSqlParser.AndContext ctx); 300 | /** 301 | * Enter a parse tree produced by the {@code Or} 302 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 303 | * @param ctx the parse tree 304 | */ 305 | void enterOr(LuceneSqlParser.OrContext ctx); 306 | /** 307 | * Exit a parse tree produced by the {@code Or} 308 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 309 | * @param ctx the parse tree 310 | */ 311 | void exitOr(LuceneSqlParser.OrContext ctx); 312 | /** 313 | * Enter a parse tree produced by the {@code Not} 314 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 315 | * @param ctx the parse tree 316 | */ 317 | void enterNot(LuceneSqlParser.NotContext ctx); 318 | /** 319 | * Exit a parse tree produced by the {@code Not} 320 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 321 | * @param ctx the parse tree 322 | */ 323 | void exitNot(LuceneSqlParser.NotContext ctx); 324 | /** 325 | * Enter a parse tree produced by the {@code AndNot} 326 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 327 | * @param ctx the parse tree 328 | */ 329 | void enterAndNot(LuceneSqlParser.AndNotContext ctx); 330 | /** 331 | * Exit a parse tree produced by the {@code AndNot} 332 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 333 | * @param ctx the parse tree 334 | */ 335 | void exitAndNot(LuceneSqlParser.AndNotContext ctx); 336 | /** 337 | * Enter a parse tree produced by the {@code OrNot} 338 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 339 | * @param ctx the parse tree 340 | */ 341 | void enterOrNot(LuceneSqlParser.OrNotContext ctx); 342 | /** 343 | * Exit a parse tree produced by the {@code OrNot} 344 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 345 | * @param ctx the parse tree 346 | */ 347 | void exitOrNot(LuceneSqlParser.OrNotContext ctx); 348 | /** 349 | * Enter a parse tree produced by {@link LuceneSqlParser#nested_predicate}. 350 | * @param ctx the parse tree 351 | */ 352 | void enterNested_predicate(LuceneSqlParser.Nested_predicateContext ctx); 353 | /** 354 | * Exit a parse tree produced by {@link LuceneSqlParser#nested_predicate}. 355 | * @param ctx the parse tree 356 | */ 357 | void exitNested_predicate(LuceneSqlParser.Nested_predicateContext ctx); 358 | /** 359 | * Enter a parse tree produced by the {@code Number} 360 | * labeled alternative in {@link LuceneSqlParser#value}. 361 | * @param ctx the parse tree 362 | */ 363 | void enterNumber(LuceneSqlParser.NumberContext ctx); 364 | /** 365 | * Exit a parse tree produced by the {@code Number} 366 | * labeled alternative in {@link LuceneSqlParser#value}. 367 | * @param ctx the parse tree 368 | */ 369 | void exitNumber(LuceneSqlParser.NumberContext ctx); 370 | /** 371 | * Enter a parse tree produced by the {@code Term} 372 | * labeled alternative in {@link LuceneSqlParser#value}. 373 | * @param ctx the parse tree 374 | */ 375 | void enterTerm(LuceneSqlParser.TermContext ctx); 376 | /** 377 | * Exit a parse tree produced by the {@code Term} 378 | * labeled alternative in {@link LuceneSqlParser#value}. 379 | * @param ctx the parse tree 380 | */ 381 | void exitTerm(LuceneSqlParser.TermContext ctx); 382 | /** 383 | * Enter a parse tree produced by the {@code Phrase} 384 | * labeled alternative in {@link LuceneSqlParser#value}. 385 | * @param ctx the parse tree 386 | */ 387 | void enterPhrase(LuceneSqlParser.PhraseContext ctx); 388 | /** 389 | * Exit a parse tree produced by the {@code Phrase} 390 | * labeled alternative in {@link LuceneSqlParser#value}. 391 | * @param ctx the parse tree 392 | */ 393 | void exitPhrase(LuceneSqlParser.PhraseContext ctx); 394 | /** 395 | * Enter a parse tree produced by the {@code Date} 396 | * labeled alternative in {@link LuceneSqlParser#value}. 397 | * @param ctx the parse tree 398 | */ 399 | void enterDate(LuceneSqlParser.DateContext ctx); 400 | /** 401 | * Exit a parse tree produced by the {@code Date} 402 | * labeled alternative in {@link LuceneSqlParser#value}. 403 | * @param ctx the parse tree 404 | */ 405 | void exitDate(LuceneSqlParser.DateContext ctx); 406 | /** 407 | * Enter a parse tree produced by the {@code MULTI_PHRASE} 408 | * labeled alternative in {@link LuceneSqlParser#value}. 409 | * @param ctx the parse tree 410 | */ 411 | void enterMULTI_PHRASE(LuceneSqlParser.MULTI_PHRASEContext ctx); 412 | /** 413 | * Exit a parse tree produced by the {@code MULTI_PHRASE} 414 | * labeled alternative in {@link LuceneSqlParser#value}. 415 | * @param ctx the parse tree 416 | */ 417 | void exitMULTI_PHRASE(LuceneSqlParser.MULTI_PHRASEContext ctx); 418 | /** 419 | * Enter a parse tree produced by {@link LuceneSqlParser#regexp}. 420 | * @param ctx the parse tree 421 | */ 422 | void enterRegexp(LuceneSqlParser.RegexpContext ctx); 423 | /** 424 | * Exit a parse tree produced by {@link LuceneSqlParser#regexp}. 425 | * @param ctx the parse tree 426 | */ 427 | void exitRegexp(LuceneSqlParser.RegexpContext ctx); 428 | /** 429 | * Enter a parse tree produced by {@link LuceneSqlParser#between}. 430 | * @param ctx the parse tree 431 | */ 432 | void enterBetween(LuceneSqlParser.BetweenContext ctx); 433 | /** 434 | * Exit a parse tree produced by {@link LuceneSqlParser#between}. 435 | * @param ctx the parse tree 436 | */ 437 | void exitBetween(LuceneSqlParser.BetweenContext ctx); 438 | /** 439 | * Enter a parse tree produced by {@link LuceneSqlParser#between_term}. 440 | * @param ctx the parse tree 441 | */ 442 | void enterBetween_term(LuceneSqlParser.Between_termContext ctx); 443 | /** 444 | * Exit a parse tree produced by {@link LuceneSqlParser#between_term}. 445 | * @param ctx the parse tree 446 | */ 447 | void exitBetween_term(LuceneSqlParser.Between_termContext ctx); 448 | /** 449 | * Enter a parse tree produced by {@link LuceneSqlParser#between_number}. 450 | * @param ctx the parse tree 451 | */ 452 | void enterBetween_number(LuceneSqlParser.Between_numberContext ctx); 453 | /** 454 | * Exit a parse tree produced by {@link LuceneSqlParser#between_number}. 455 | * @param ctx the parse tree 456 | */ 457 | void exitBetween_number(LuceneSqlParser.Between_numberContext ctx); 458 | /** 459 | * Enter a parse tree produced by {@link LuceneSqlParser#like}. 460 | * @param ctx the parse tree 461 | */ 462 | void enterLike(LuceneSqlParser.LikeContext ctx); 463 | /** 464 | * Exit a parse tree produced by {@link LuceneSqlParser#like}. 465 | * @param ctx the parse tree 466 | */ 467 | void exitLike(LuceneSqlParser.LikeContext ctx); 468 | /** 469 | * Enter a parse tree produced by {@link LuceneSqlParser#in}. 470 | * @param ctx the parse tree 471 | */ 472 | void enterIn(LuceneSqlParser.InContext ctx); 473 | /** 474 | * Exit a parse tree produced by {@link LuceneSqlParser#in}. 475 | * @param ctx the parse tree 476 | */ 477 | void exitIn(LuceneSqlParser.InContext ctx); 478 | /** 479 | * Enter a parse tree produced by {@link LuceneSqlParser#value_list}. 480 | * @param ctx the parse tree 481 | */ 482 | void enterValue_list(LuceneSqlParser.Value_listContext ctx); 483 | /** 484 | * Exit a parse tree produced by {@link LuceneSqlParser#value_list}. 485 | * @param ctx the parse tree 486 | */ 487 | void exitValue_list(LuceneSqlParser.Value_listContext ctx); 488 | /** 489 | * Enter a parse tree produced by {@link LuceneSqlParser#number_list}. 490 | * @param ctx the parse tree 491 | */ 492 | void enterNumber_list(LuceneSqlParser.Number_listContext ctx); 493 | /** 494 | * Exit a parse tree produced by {@link LuceneSqlParser#number_list}. 495 | * @param ctx the parse tree 496 | */ 497 | void exitNumber_list(LuceneSqlParser.Number_listContext ctx); 498 | /** 499 | * Enter a parse tree produced by {@link LuceneSqlParser#date_list}. 500 | * @param ctx the parse tree 501 | */ 502 | void enterDate_list(LuceneSqlParser.Date_listContext ctx); 503 | /** 504 | * Exit a parse tree produced by {@link LuceneSqlParser#date_list}. 505 | * @param ctx the parse tree 506 | */ 507 | void exitDate_list(LuceneSqlParser.Date_listContext ctx); 508 | /** 509 | * Enter a parse tree produced by {@link LuceneSqlParser#term_list}. 510 | * @param ctx the parse tree 511 | */ 512 | void enterTerm_list(LuceneSqlParser.Term_listContext ctx); 513 | /** 514 | * Exit a parse tree produced by {@link LuceneSqlParser#term_list}. 515 | * @param ctx the parse tree 516 | */ 517 | void exitTerm_list(LuceneSqlParser.Term_listContext ctx); 518 | /** 519 | * Enter a parse tree produced by {@link LuceneSqlParser#phrase_list}. 520 | * @param ctx the parse tree 521 | */ 522 | void enterPhrase_list(LuceneSqlParser.Phrase_listContext ctx); 523 | /** 524 | * Exit a parse tree produced by {@link LuceneSqlParser#phrase_list}. 525 | * @param ctx the parse tree 526 | */ 527 | void exitPhrase_list(LuceneSqlParser.Phrase_listContext ctx); 528 | } -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/antlr/generated/LuceneSqlVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/bbejeck/dev/github_clones/sql-for-lucene/src/main/java/LuceneSql.g4 by ANTLR 4.5.1 2 | package bbejeck.sql.antlr.generated; 3 | import org.antlr.v4.runtime.tree.ParseTreeVisitor; 4 | 5 | /** 6 | * This interface defines a complete generic visitor for a parse tree produced 7 | * by {@link LuceneSqlParser}. 8 | * 9 | * @param The return type of the visit operation. Use {@link Void} for 10 | * operations with no return type. 11 | */ 12 | public interface LuceneSqlVisitor extends ParseTreeVisitor { 13 | /** 14 | * Visit a parse tree produced by {@link LuceneSqlParser#query}. 15 | * @param ctx the parse tree 16 | * @return the visitor result 17 | */ 18 | T visitQuery(LuceneSqlParser.QueryContext ctx); 19 | /** 20 | * Visit a parse tree produced by {@link LuceneSqlParser#select_stmt}. 21 | * @param ctx the parse tree 22 | * @return the visitor result 23 | */ 24 | T visitSelect_stmt(LuceneSqlParser.Select_stmtContext ctx); 25 | /** 26 | * Visit a parse tree produced by {@link LuceneSqlParser#from_stmt}. 27 | * @param ctx the parse tree 28 | * @return the visitor result 29 | */ 30 | T visitFrom_stmt(LuceneSqlParser.From_stmtContext ctx); 31 | /** 32 | * Visit a parse tree produced by {@link LuceneSqlParser#where_stmt}. 33 | * @param ctx the parse tree 34 | * @return the visitor result 35 | */ 36 | T visitWhere_stmt(LuceneSqlParser.Where_stmtContext ctx); 37 | /** 38 | * Visit a parse tree produced by {@link LuceneSqlParser#limit_stmt}. 39 | * @param ctx the parse tree 40 | * @return the visitor result 41 | */ 42 | T visitLimit_stmt(LuceneSqlParser.Limit_stmtContext ctx); 43 | /** 44 | * Visit a parse tree produced by {@link LuceneSqlParser#search_condition}. 45 | * @param ctx the parse tree 46 | * @return the visitor result 47 | */ 48 | T visitSearch_condition(LuceneSqlParser.Search_conditionContext ctx); 49 | /** 50 | * Visit a parse tree produced by {@link LuceneSqlParser#predicate}. 51 | * @param ctx the parse tree 52 | * @return the visitor result 53 | */ 54 | T visitPredicate(LuceneSqlParser.PredicateContext ctx); 55 | /** 56 | * Visit a parse tree produced by {@link LuceneSqlParser#comparison_predicate}. 57 | * @param ctx the parse tree 58 | * @return the visitor result 59 | */ 60 | T visitComparison_predicate(LuceneSqlParser.Comparison_predicateContext ctx); 61 | /** 62 | * Visit a parse tree produced by {@link LuceneSqlParser#function_predicate}. 63 | * @param ctx the parse tree 64 | * @return the visitor result 65 | */ 66 | T visitFunction_predicate(LuceneSqlParser.Function_predicateContext ctx); 67 | /** 68 | * Visit a parse tree produced by {@link LuceneSqlParser#field}. 69 | * @param ctx the parse tree 70 | * @return the visitor result 71 | */ 72 | T visitField(LuceneSqlParser.FieldContext ctx); 73 | /** 74 | * Visit a parse tree produced by the {@code Equals} 75 | * labeled alternative in {@link LuceneSqlParser#comparison_op}. 76 | * @param ctx the parse tree 77 | * @return the visitor result 78 | */ 79 | T visitEquals(LuceneSqlParser.EqualsContext ctx); 80 | /** 81 | * Visit a parse tree produced by the {@code NotEqual} 82 | * labeled alternative in {@link LuceneSqlParser#comparison_op}. 83 | * @param ctx the parse tree 84 | * @return the visitor result 85 | */ 86 | T visitNotEqual(LuceneSqlParser.NotEqualContext ctx); 87 | /** 88 | * Visit a parse tree produced by {@link LuceneSqlParser#range_op}. 89 | * @param ctx the parse tree 90 | * @return the visitor result 91 | */ 92 | T visitRange_op(LuceneSqlParser.Range_opContext ctx); 93 | /** 94 | * Visit a parse tree produced by the {@code greaterThanNumber} 95 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 96 | * @param ctx the parse tree 97 | * @return the visitor result 98 | */ 99 | T visitGreaterThanNumber(LuceneSqlParser.GreaterThanNumberContext ctx); 100 | /** 101 | * Visit a parse tree produced by the {@code greaterThanTerm} 102 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 103 | * @param ctx the parse tree 104 | * @return the visitor result 105 | */ 106 | T visitGreaterThanTerm(LuceneSqlParser.GreaterThanTermContext ctx); 107 | /** 108 | * Visit a parse tree produced by the {@code greaterThanDate} 109 | * labeled alternative in {@link LuceneSqlParser#greater_than}. 110 | * @param ctx the parse tree 111 | * @return the visitor result 112 | */ 113 | T visitGreaterThanDate(LuceneSqlParser.GreaterThanDateContext ctx); 114 | /** 115 | * Visit a parse tree produced by the {@code greaterThanEqNumber} 116 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 117 | * @param ctx the parse tree 118 | * @return the visitor result 119 | */ 120 | T visitGreaterThanEqNumber(LuceneSqlParser.GreaterThanEqNumberContext ctx); 121 | /** 122 | * Visit a parse tree produced by the {@code greaterThanEqTerm} 123 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 124 | * @param ctx the parse tree 125 | * @return the visitor result 126 | */ 127 | T visitGreaterThanEqTerm(LuceneSqlParser.GreaterThanEqTermContext ctx); 128 | /** 129 | * Visit a parse tree produced by the {@code greaterThanEqDate} 130 | * labeled alternative in {@link LuceneSqlParser#greater_than_equals}. 131 | * @param ctx the parse tree 132 | * @return the visitor result 133 | */ 134 | T visitGreaterThanEqDate(LuceneSqlParser.GreaterThanEqDateContext ctx); 135 | /** 136 | * Visit a parse tree produced by the {@code lessThanNumber} 137 | * labeled alternative in {@link LuceneSqlParser#less_than}. 138 | * @param ctx the parse tree 139 | * @return the visitor result 140 | */ 141 | T visitLessThanNumber(LuceneSqlParser.LessThanNumberContext ctx); 142 | /** 143 | * Visit a parse tree produced by the {@code lessThanTerm} 144 | * labeled alternative in {@link LuceneSqlParser#less_than}. 145 | * @param ctx the parse tree 146 | * @return the visitor result 147 | */ 148 | T visitLessThanTerm(LuceneSqlParser.LessThanTermContext ctx); 149 | /** 150 | * Visit a parse tree produced by the {@code lessThanDate} 151 | * labeled alternative in {@link LuceneSqlParser#less_than}. 152 | * @param ctx the parse tree 153 | * @return the visitor result 154 | */ 155 | T visitLessThanDate(LuceneSqlParser.LessThanDateContext ctx); 156 | /** 157 | * Visit a parse tree produced by the {@code lessThanEqNumber} 158 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 159 | * @param ctx the parse tree 160 | * @return the visitor result 161 | */ 162 | T visitLessThanEqNumber(LuceneSqlParser.LessThanEqNumberContext ctx); 163 | /** 164 | * Visit a parse tree produced by the {@code lessThanEqTerm} 165 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 166 | * @param ctx the parse tree 167 | * @return the visitor result 168 | */ 169 | T visitLessThanEqTerm(LuceneSqlParser.LessThanEqTermContext ctx); 170 | /** 171 | * Visit a parse tree produced by the {@code lessThanEqDate} 172 | * labeled alternative in {@link LuceneSqlParser#less_than_equals}. 173 | * @param ctx the parse tree 174 | * @return the visitor result 175 | */ 176 | T visitLessThanEqDate(LuceneSqlParser.LessThanEqDateContext ctx); 177 | /** 178 | * Visit a parse tree produced by the {@code And} 179 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 180 | * @param ctx the parse tree 181 | * @return the visitor result 182 | */ 183 | T visitAnd(LuceneSqlParser.AndContext ctx); 184 | /** 185 | * Visit a parse tree produced by the {@code Or} 186 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 187 | * @param ctx the parse tree 188 | * @return the visitor result 189 | */ 190 | T visitOr(LuceneSqlParser.OrContext ctx); 191 | /** 192 | * Visit a parse tree produced by the {@code Not} 193 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 194 | * @param ctx the parse tree 195 | * @return the visitor result 196 | */ 197 | T visitNot(LuceneSqlParser.NotContext ctx); 198 | /** 199 | * Visit a parse tree produced by the {@code AndNot} 200 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 201 | * @param ctx the parse tree 202 | * @return the visitor result 203 | */ 204 | T visitAndNot(LuceneSqlParser.AndNotContext ctx); 205 | /** 206 | * Visit a parse tree produced by the {@code OrNot} 207 | * labeled alternative in {@link LuceneSqlParser#boolean_op}. 208 | * @param ctx the parse tree 209 | * @return the visitor result 210 | */ 211 | T visitOrNot(LuceneSqlParser.OrNotContext ctx); 212 | /** 213 | * Visit a parse tree produced by {@link LuceneSqlParser#nested_predicate}. 214 | * @param ctx the parse tree 215 | * @return the visitor result 216 | */ 217 | T visitNested_predicate(LuceneSqlParser.Nested_predicateContext ctx); 218 | /** 219 | * Visit a parse tree produced by the {@code Number} 220 | * labeled alternative in {@link LuceneSqlParser#value}. 221 | * @param ctx the parse tree 222 | * @return the visitor result 223 | */ 224 | T visitNumber(LuceneSqlParser.NumberContext ctx); 225 | /** 226 | * Visit a parse tree produced by the {@code Term} 227 | * labeled alternative in {@link LuceneSqlParser#value}. 228 | * @param ctx the parse tree 229 | * @return the visitor result 230 | */ 231 | T visitTerm(LuceneSqlParser.TermContext ctx); 232 | /** 233 | * Visit a parse tree produced by the {@code Phrase} 234 | * labeled alternative in {@link LuceneSqlParser#value}. 235 | * @param ctx the parse tree 236 | * @return the visitor result 237 | */ 238 | T visitPhrase(LuceneSqlParser.PhraseContext ctx); 239 | /** 240 | * Visit a parse tree produced by the {@code Date} 241 | * labeled alternative in {@link LuceneSqlParser#value}. 242 | * @param ctx the parse tree 243 | * @return the visitor result 244 | */ 245 | T visitDate(LuceneSqlParser.DateContext ctx); 246 | /** 247 | * Visit a parse tree produced by the {@code MULTI_PHRASE} 248 | * labeled alternative in {@link LuceneSqlParser#value}. 249 | * @param ctx the parse tree 250 | * @return the visitor result 251 | */ 252 | T visitMULTI_PHRASE(LuceneSqlParser.MULTI_PHRASEContext ctx); 253 | /** 254 | * Visit a parse tree produced by {@link LuceneSqlParser#regexp}. 255 | * @param ctx the parse tree 256 | * @return the visitor result 257 | */ 258 | T visitRegexp(LuceneSqlParser.RegexpContext ctx); 259 | /** 260 | * Visit a parse tree produced by {@link LuceneSqlParser#between}. 261 | * @param ctx the parse tree 262 | * @return the visitor result 263 | */ 264 | T visitBetween(LuceneSqlParser.BetweenContext ctx); 265 | /** 266 | * Visit a parse tree produced by {@link LuceneSqlParser#between_term}. 267 | * @param ctx the parse tree 268 | * @return the visitor result 269 | */ 270 | T visitBetween_term(LuceneSqlParser.Between_termContext ctx); 271 | /** 272 | * Visit a parse tree produced by {@link LuceneSqlParser#between_number}. 273 | * @param ctx the parse tree 274 | * @return the visitor result 275 | */ 276 | T visitBetween_number(LuceneSqlParser.Between_numberContext ctx); 277 | /** 278 | * Visit a parse tree produced by {@link LuceneSqlParser#like}. 279 | * @param ctx the parse tree 280 | * @return the visitor result 281 | */ 282 | T visitLike(LuceneSqlParser.LikeContext ctx); 283 | /** 284 | * Visit a parse tree produced by {@link LuceneSqlParser#in}. 285 | * @param ctx the parse tree 286 | * @return the visitor result 287 | */ 288 | T visitIn(LuceneSqlParser.InContext ctx); 289 | /** 290 | * Visit a parse tree produced by {@link LuceneSqlParser#value_list}. 291 | * @param ctx the parse tree 292 | * @return the visitor result 293 | */ 294 | T visitValue_list(LuceneSqlParser.Value_listContext ctx); 295 | /** 296 | * Visit a parse tree produced by {@link LuceneSqlParser#number_list}. 297 | * @param ctx the parse tree 298 | * @return the visitor result 299 | */ 300 | T visitNumber_list(LuceneSqlParser.Number_listContext ctx); 301 | /** 302 | * Visit a parse tree produced by {@link LuceneSqlParser#date_list}. 303 | * @param ctx the parse tree 304 | * @return the visitor result 305 | */ 306 | T visitDate_list(LuceneSqlParser.Date_listContext ctx); 307 | /** 308 | * Visit a parse tree produced by {@link LuceneSqlParser#term_list}. 309 | * @param ctx the parse tree 310 | * @return the visitor result 311 | */ 312 | T visitTerm_list(LuceneSqlParser.Term_listContext ctx); 313 | /** 314 | * Visit a parse tree produced by {@link LuceneSqlParser#phrase_list}. 315 | * @param ctx the parse tree 316 | * @return the visitor result 317 | */ 318 | T visitPhrase_list(LuceneSqlParser.Phrase_listContext ctx); 319 | } -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/BooleanClauseBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import org.apache.lucene.search.BooleanClause; 25 | import org.apache.lucene.search.BooleanQuery; 26 | 27 | import java.util.List; 28 | 29 | /** 30 | * User: Bill Bejeck 31 | * Date: 8/11/14 32 | * Time: 9:40 PM 33 | */ 34 | public class BooleanClauseBuilder { 35 | 36 | private String field; 37 | private String text; 38 | private List textValues; 39 | private List booleanClauses; 40 | 41 | public void setBooleanClauses(List booleanClauses) { 42 | this.booleanClauses = booleanClauses; 43 | } 44 | 45 | private BooleanClause.Occur occur; 46 | private QueryType queryType; 47 | 48 | public void setField(String field) { 49 | this.field = field; 50 | } 51 | 52 | public void setText(String text) { 53 | this.text = text; 54 | } 55 | 56 | public void setQueryType(QueryType queryType) { 57 | this.queryType = queryType; 58 | } 59 | 60 | public void setTextValues(List textValues) { 61 | this.textValues = textValues; 62 | } 63 | 64 | public void setOccur(BooleanClause.Occur occur) { 65 | this.occur = occur; 66 | } 67 | 68 | public BooleanClause build() { 69 | if (occur == null) { 70 | occur = BooleanClause.Occur.MUST; 71 | } 72 | 73 | if (booleanClauses == null || booleanClauses.isEmpty()) { 74 | return new BooleanClause(queryType.query(field, text), occur); 75 | } 76 | 77 | BooleanQuery booleanQuery = LuceneQueryFunctions.toBooleanQuery.apply(booleanClauses); 78 | return new BooleanClause(booleanQuery, occur); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/FilterType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import org.apache.lucene.index.Term; 25 | import org.apache.lucene.queries.TermsFilter; 26 | import org.apache.lucene.search.Filter; 27 | 28 | import java.util.Collection; 29 | import java.util.List; 30 | import java.util.function.Function; 31 | import java.util.stream.Collectors; 32 | 33 | /** 34 | * User: Bill Bejeck 35 | * Date: 2/17/15 36 | * Time: 9:51 PM 37 | */ 38 | public enum FilterType implements LuceneQueryFunctions,LuceneAnalyzingFunctions { 39 | 40 | TERMS_FILTER { 41 | @Override 42 | Filter filter(String field, Collection filterValues) { 43 | List filterTerms = filterValues.stream().map(createFilterTerm.apply(field)).collect(Collectors.toList()); 44 | return new TermsFilter(filterTerms); 45 | } 46 | }, 47 | 48 | TERM_RANGE_FILTER{ 49 | @Override 50 | Filter filter(String field, Collection filterValues) { 51 | throw new RuntimeException("Not Implemented"); 52 | } 53 | }, 54 | 55 | NUMERIC_RANGE_FILTER{ 56 | @Override 57 | Filter filter(String field, Collection filterValues) { 58 | throw new RuntimeException("Not Implemented"); 59 | } 60 | }, 61 | 62 | QUERY_FILTER{ 63 | @Override 64 | Filter filter(String field, Collection filterValues) { 65 | throw new RuntimeException("Not Implemented"); 66 | } 67 | }; 68 | 69 | abstract Filter filter(String field,Collection filterValues); 70 | 71 | Function> createFilterTerm = f -> lettersNumbersTrimLowerCase.andThen(termFunction.apply(f)); 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/LuceneAnalyzingFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import java.util.function.Function; 25 | 26 | import static com.google.common.base.CharMatcher.JAVA_LETTER_OR_DIGIT; 27 | import static com.google.common.base.CharMatcher.WHITESPACE; 28 | 29 | /** 30 | * User: Bill Bejeck 31 | * Date: 2/17/15 32 | * Time: 10:03 PM 33 | */ 34 | public interface LuceneAnalyzingFunctions { 35 | 36 | Function removeMultipleSpace = s -> s.replaceAll("\\s+", " "); 37 | Function lettersNumbersWhitespace = s -> s.replaceAll("[^a-zA-Z0-9\\s]", ""); 38 | Function lettersNumbersWildcard = s -> s.replaceAll("[^a-zA-Z0-9*?]", ""); 39 | Function removeWhitespace = WHITESPACE::removeFrom; 40 | Function trim = String::trim; 41 | Function lettersNumbers = JAVA_LETTER_OR_DIGIT::retainFrom; 42 | Function lowerCase = String::toLowerCase; 43 | Function lettersNumbersLowercase = lettersNumbers.andThen(lowerCase); 44 | Function lettersNumbersTrimLowerCase = lettersNumbersLowercase.andThen(removeWhitespace); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/LuceneQueryAssembler.java: -------------------------------------------------------------------------------- 1 | package bbejeck.sql.lucene; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import org.apache.lucene.search.Query; 5 | import org.apache.lucene.search.TermQuery; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * User: Bill Bejeck 11 | * Date: 6/12/14 12 | * Time: 10:00 PM 13 | */ 14 | public class LuceneQueryAssembler { 15 | 16 | private String indexPath; 17 | private ImmutableList fields; 18 | private ImmutableList searchClauses; 19 | private Query query; 20 | 21 | public void setIndexPath(String indexPath) { 22 | this.indexPath = indexPath; 23 | } 24 | 25 | public void setFields(List fields) { 26 | this.fields = ImmutableList.builder().addAll(fields).build(); 27 | } 28 | 29 | public String getIndexPath() { 30 | return indexPath; 31 | } 32 | 33 | public List getFields() { 34 | return fields; 35 | } 36 | 37 | public Query getQuery() { 38 | return query; 39 | } 40 | 41 | public void init(){ 42 | 43 | } 44 | 45 | public void finish(){ 46 | 47 | } 48 | 49 | public static class Builder { 50 | private String indexPath; 51 | private List fields; 52 | private TermQuery termQuery; 53 | 54 | public Builder indexPath(String indexPath) { 55 | this.indexPath = indexPath; 56 | return this; 57 | } 58 | 59 | public Builder fields(List fields) { 60 | this.fields = new ImmutableList.Builder().addAll(fields).build(); 61 | return this; 62 | } 63 | 64 | public Builder termQuery(TermQuery termQuery) { 65 | this.termQuery = termQuery; 66 | return this; 67 | } 68 | 69 | 70 | 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/LuceneQueryFunctions.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * * 4 | * 5 | * 6 | * Copyright 2015 Bill Bejeck 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * 21 | */ 22 | 23 | package bbejeck.sql.lucene; 24 | 25 | import bbejeck.sql.util.Collectors; 26 | import bbejeck.sql.util.ThrowingBiFunction; 27 | import com.google.common.base.Splitter; 28 | import com.google.common.collect.Lists; 29 | import org.apache.lucene.index.Term; 30 | import org.apache.lucene.queries.BooleanFilter; 31 | import org.apache.lucene.queries.FilterClause; 32 | import org.apache.lucene.search.*; 33 | 34 | import java.util.List; 35 | import java.util.function.BiFunction; 36 | import java.util.function.Function; 37 | import java.util.stream.Stream; 38 | 39 | /** 40 | * User: Bill Bejeck 41 | * Date: 8/12/14 42 | * Time: 11:25 PM 43 | */ 44 | public interface LuceneQueryFunctions { 45 | 46 | 47 | BiFunction createTerm = Term::new; 48 | 49 | BiFunction>> toBooleanClause = (f, t) -> qt -> bco -> new BooleanClause(qt.query(f, t), bco); 50 | 51 | ThrowingBiFunction, Query> toQuery = (term, clazz) -> clazz.getConstructor(Term.class).newInstance(term); 52 | 53 | Function> fromOccurToClause = occur -> query -> new BooleanClause(query,occur); 54 | Function extractBooleanClause = bq -> bq.getClauses()[0]; 55 | Function toOrBooleanClause = fromOccurToClause.apply(BooleanClause.Occur.SHOULD); 56 | Function toMustBooleanClause = fromOccurToClause.apply(BooleanClause.Occur.MUST); 57 | Function toNotBooleanClause = fromOccurToClause.apply(BooleanClause.Occur.MUST_NOT); 58 | Function toTermQuery = t -> toQuery.apply(t, TermQuery.class); 59 | Function> termFunction = field -> text -> createTerm.apply(field, text); 60 | Function> toWordStream = s -> Lists.newArrayList(Splitter.on(" ").split(s)).stream(); 61 | BiFunction toPhraseQuery = (field, text) -> 62 | toWordStream.apply(text).map(termFunction.apply(field)).collect(Collectors.nonParallelCollect(PhraseQuery::new, PhraseQuery::add)); 63 | 64 | Function, BooleanQuery> toBooleanQuery = l -> l.stream().collect(Collectors.nonParallelCollect(BooleanQuery::new, BooleanQuery::add)); 65 | Function,BooleanFilter> toBooleanFilter = filters -> filters.stream().collect(Collectors.nonParallelCollect(BooleanFilter::new, BooleanFilter::add)); 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/LuceneQueryListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import bbejeck.sql.antlr.generated.LuceneSqlBaseListener; 25 | import bbejeck.sql.antlr.generated.LuceneSqlParser; 26 | import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.Sets; 27 | import com.google.common.base.Joiner; 28 | import com.google.common.collect.Lists; 29 | import org.antlr.v4.runtime.misc.NotNull; 30 | import org.antlr.v4.runtime.tree.TerminalNode; 31 | import org.apache.lucene.queries.FilterClause; 32 | import org.apache.lucene.search.BooleanClause; 33 | 34 | import java.util.List; 35 | import java.util.Set; 36 | import java.util.Stack; 37 | import java.util.function.Function; 38 | import java.util.stream.Collectors; 39 | 40 | /** 41 | * User: Bill Bejeck 42 | * Date: 6/12/14 43 | * Time: 9:54 PM 44 | */ 45 | public class LuceneQueryListener extends LuceneSqlBaseListener { 46 | 47 | private String indexPath; 48 | private int limit; 49 | private Set selectedFields = Sets.newHashSet(); 50 | private List filterClauses = Lists.newArrayList(); 51 | private Stack booleanClauseBuilders = new Stack<>(); 52 | private Stack> booleanClausesListStack = new Stack<>(); 53 | private List completeBooleanClauseList = Lists.newArrayList(); 54 | private Function, String>> toJoinedFunction = j -> j::join; 55 | private Function, String> toJoinedString = toJoinedFunction.apply(Joiner.on(':').skipNulls()); 56 | private QueryParseResults.Builder queryResultsBuilder = QueryParseResults.newBuilder(); 57 | 58 | 59 | @Override 60 | public void exitSelect_stmt(@NotNull LuceneSqlParser.Select_stmtContext ctx) { 61 | selectedFields = ctx.FIELD().stream().map(TerminalNode::getText).collect(Collectors.toSet()); 62 | } 63 | 64 | @Override 65 | public void enterQuery(@NotNull LuceneSqlParser.QueryContext ctx) { 66 | booleanClausesListStack.push(Lists.newArrayList()); 67 | } 68 | 69 | @Override 70 | public void exitQuery(@NotNull LuceneSqlParser.QueryContext ctx) { 71 | List booleanClauses = booleanClausesListStack.pop(); 72 | completeBooleanClauseList = Lists.newArrayList(booleanClauses); 73 | } 74 | 75 | @Override 76 | public void exitPredicate(@NotNull LuceneSqlParser.PredicateContext ctx) { 77 | booleanClausesListStack.peek().add(booleanClauseBuilders.pop().build()); 78 | } 79 | 80 | @Override 81 | public void enterPredicate(@NotNull LuceneSqlParser.PredicateContext ctx) { 82 | booleanClauseBuilders.push(new BooleanClauseBuilder()); 83 | } 84 | 85 | 86 | @Override 87 | public void enterLessThanNumber(@NotNull LuceneSqlParser.LessThanNumberContext ctx) { 88 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 89 | builder.setText(QueryType.UNBOUNDED + ":" + ctx.NUMBER()+":false"); 90 | builder.setQueryType(QueryType.INTEGER_RANGE_UNBOUNDED); 91 | } 92 | 93 | @Override 94 | public void enterLessThanTerm(@NotNull LuceneSqlParser.LessThanTermContext ctx) { 95 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 96 | builder.setText(QueryType.UNBOUNDED + ":" + ctx.TERM()+":false"); 97 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 98 | } 99 | 100 | @Override 101 | public void enterLessThanDate(@NotNull LuceneSqlParser.LessThanDateContext ctx) { 102 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 103 | builder.setText(QueryType.UNBOUNDED + ":" + ctx.DATE()+":false"); 104 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 105 | } 106 | 107 | @Override 108 | public void enterLessThanEqNumber(@NotNull LuceneSqlParser.LessThanEqNumberContext ctx) { 109 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 110 | builder.setText(QueryType.UNBOUNDED + ":" + ctx.NUMBER()+":true"); 111 | builder.setQueryType(QueryType.INTEGER_RANGE_UNBOUNDED); 112 | } 113 | 114 | @Override 115 | public void enterLessThanEqTerm(@NotNull LuceneSqlParser.LessThanEqTermContext ctx) { 116 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 117 | builder.setText(QueryType.UNBOUNDED + ":" + ctx.TERM()+":true"); 118 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 119 | } 120 | 121 | @Override 122 | public void enterLessThanEqDate(@NotNull LuceneSqlParser.LessThanEqDateContext ctx) { 123 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 124 | builder.setText(QueryType.UNBOUNDED + ":" + ctx.DATE()+":true"); 125 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 126 | } 127 | 128 | @Override 129 | public void enterGreaterThanNumber(@NotNull LuceneSqlParser.GreaterThanNumberContext ctx) { 130 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 131 | builder.setText(ctx.NUMBER().getText()+":"+QueryType.UNBOUNDED+":false"); 132 | builder.setQueryType(QueryType.INTEGER_RANGE_UNBOUNDED); 133 | } 134 | 135 | @Override 136 | public void enterGreaterThanTerm(@NotNull LuceneSqlParser.GreaterThanTermContext ctx) { 137 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 138 | builder.setText(ctx.TERM()+":"+QueryType.UNBOUNDED+":false"); 139 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 140 | } 141 | 142 | @Override 143 | public void enterGreaterThanDate(@NotNull LuceneSqlParser.GreaterThanDateContext ctx) { 144 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 145 | builder.setText(ctx.DATE().getText()+":"+QueryType.UNBOUNDED+":false"); 146 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 147 | } 148 | 149 | @Override 150 | public void enterGreaterThanEqNumber(@NotNull LuceneSqlParser.GreaterThanEqNumberContext ctx) { 151 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 152 | builder.setText(ctx.NUMBER().getText()+":"+QueryType.UNBOUNDED+":true"); 153 | builder.setQueryType(QueryType.INTEGER_RANGE_UNBOUNDED); 154 | } 155 | 156 | @Override 157 | public void enterGreaterThanEqTerm(@NotNull LuceneSqlParser.GreaterThanEqTermContext ctx) { 158 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 159 | builder.setText(ctx.TERM()+":"+QueryType.UNBOUNDED+":true"); 160 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 161 | } 162 | 163 | @Override 164 | public void enterGreaterThanEqDate(@NotNull LuceneSqlParser.GreaterThanEqDateContext ctx) { 165 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 166 | builder.setText(ctx.DATE().getText()+":"+QueryType.UNBOUNDED+":true"); 167 | builder.setQueryType(QueryType.TERM_RANGE_UNBOUNDED); 168 | } 169 | 170 | @Override 171 | public void enterAnd(@NotNull LuceneSqlParser.AndContext ctx) { 172 | booleanClauseBuilders.peek().setOccur(BooleanClause.Occur.MUST); 173 | } 174 | 175 | @Override 176 | public void enterIn(@NotNull LuceneSqlParser.InContext ctx) { 177 | if (ctx.NOT() != null) { 178 | booleanClauseBuilders.peek().setOccur(BooleanClause.Occur.MUST_NOT); 179 | } 180 | } 181 | 182 | @Override 183 | public void enterNotEqual(@NotNull LuceneSqlParser.NotEqualContext ctx) { 184 | booleanClauseBuilders.peek().setOccur(BooleanClause.Occur.MUST_NOT); 185 | } 186 | 187 | @Override 188 | public void enterAndNot(@NotNull LuceneSqlParser.AndNotContext ctx) { 189 | booleanClauseBuilders.peek().setOccur(BooleanClause.Occur.MUST_NOT); 190 | } 191 | 192 | @Override 193 | public void enterNot(@NotNull LuceneSqlParser.NotContext ctx) { 194 | booleanClauseBuilders.peek().setOccur(BooleanClause.Occur.MUST_NOT); 195 | } 196 | 197 | @Override 198 | public void enterOr(@NotNull LuceneSqlParser.OrContext ctx) { 199 | booleanClauseBuilders.peek().setOccur(BooleanClause.Occur.SHOULD); 200 | } 201 | 202 | @Override 203 | public void enterRegexp(@NotNull LuceneSqlParser.RegexpContext ctx) { 204 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 205 | builder.setText(ctx.WILD_CARD().getText()); 206 | builder.setQueryType(QueryType.REGEXP); 207 | } 208 | 209 | @Override 210 | public void enterTerm(@NotNull LuceneSqlParser.TermContext ctx) { 211 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 212 | builder.setText(ctx.TERM().getText()); 213 | builder.setQueryType(QueryType.TERM); 214 | } 215 | 216 | @Override 217 | public void enterNumber(@NotNull LuceneSqlParser.NumberContext ctx) { 218 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 219 | builder.setText(ctx.NUMBER().getText()); 220 | builder.setQueryType(QueryType.TERM ); 221 | } 222 | 223 | @Override 224 | public void enterDate(@NotNull LuceneSqlParser.DateContext ctx) { 225 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 226 | builder.setText(ctx.DATE().getText()); 227 | builder.setQueryType(QueryType.TERM); 228 | } 229 | 230 | @Override 231 | public void enterPhrase(@NotNull LuceneSqlParser.PhraseContext ctx) { 232 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 233 | builder.setText(ctx.PHRASE().getText()); 234 | builder.setQueryType(QueryType.PHRASE); 235 | } 236 | 237 | @Override 238 | public void enterBetween_term(@NotNull LuceneSqlParser.Between_termContext ctx) { 239 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 240 | builder.setText(toJoinedString.apply(ctx.TERM())); 241 | builder.setQueryType(QueryType.TERM_RANGE); 242 | } 243 | 244 | @Override 245 | public void enterBetween_number(@NotNull LuceneSqlParser.Between_numberContext ctx) { 246 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 247 | builder.setText(toJoinedString.apply(ctx.NUMBER())); 248 | builder.setQueryType(QueryType.INTEGER_RANGE); 249 | } 250 | 251 | @Override 252 | public void enterLike(@NotNull LuceneSqlParser.LikeContext ctx) { 253 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 254 | builder.setText(ctx.WILD_CARD().getText()); 255 | builder.setQueryType(QueryType.WILDCARD); 256 | } 257 | 258 | @Override 259 | public void enterNumber_list(@NotNull LuceneSqlParser.Number_listContext ctx) { 260 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 261 | builder.setText(toJoinedString.apply(ctx.NUMBER())); 262 | builder.setQueryType(QueryType.BOOLEAN_OR_LIST); 263 | } 264 | 265 | @Override 266 | public void enterTerm_list(@NotNull LuceneSqlParser.Term_listContext ctx) { 267 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 268 | builder.setText(toJoinedString.apply(ctx.TERM())); 269 | builder.setQueryType(QueryType.BOOLEAN_OR_LIST); 270 | } 271 | 272 | @Override 273 | public void enterPhrase_list(@NotNull LuceneSqlParser.Phrase_listContext ctx) { 274 | BooleanClauseBuilder builder = booleanClauseBuilders.peek(); 275 | List inputs = Lists.newArrayList(); 276 | inputs.addAll(ctx.PHRASE()); 277 | inputs.addAll(ctx.TERM()); 278 | builder.setText(toJoinedString.apply(inputs)); 279 | builder.setQueryType(QueryType.BOOLEAN_PHRASE_LIST); 280 | } 281 | 282 | @Override 283 | public void enterNested_predicate(@NotNull LuceneSqlParser.Nested_predicateContext ctx) { 284 | booleanClausesListStack.push(Lists.newArrayList()); 285 | booleanClauseBuilders.push(new BooleanClauseBuilder()); 286 | } 287 | 288 | @Override 289 | public void exitNested_predicate(@NotNull LuceneSqlParser.Nested_predicateContext ctx) { 290 | List nestedClauses = booleanClausesListStack.pop(); 291 | BooleanClauseBuilder queryBuilder = booleanClauseBuilders.pop(); 292 | queryBuilder.setBooleanClauses(nestedClauses); 293 | booleanClausesListStack.peek().add(queryBuilder.build()); 294 | } 295 | 296 | @Override 297 | public void enterField(@NotNull LuceneSqlParser.FieldContext ctx) { 298 | booleanClauseBuilders.peek().setField(ctx.FIELD().getText()); 299 | } 300 | 301 | @Override 302 | public void enterLimit_stmt(@NotNull LuceneSqlParser.Limit_stmtContext ctx) { 303 | this.limit = Integer.parseInt(ctx.NUMBER().getText()); 304 | } 305 | 306 | @Override 307 | public void exitFrom_stmt(@NotNull LuceneSqlParser.From_stmtContext ctx) { 308 | this.indexPath = ctx.PATH().toString(); 309 | } 310 | 311 | public QueryParseResults getParseResults() { 312 | return queryResultsBuilder.withBooleanClausesList(this.completeBooleanClauseList) 313 | .withFilterClausesList(this.filterClauses) 314 | .withIndexPath(this.indexPath) 315 | .withLimit(this.limit) 316 | .withSelectFields(this.selectedFields).build(); 317 | 318 | } 319 | 320 | 321 | } 322 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/LuceneQueryVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import bbejeck.sql.antlr.generated.LuceneSqlBaseVisitor; 25 | import bbejeck.sql.antlr.generated.LuceneSqlParser; 26 | import org.antlr.v4.runtime.misc.NotNull; 27 | 28 | /** 29 | * User: Bill Bejeck 30 | * Date: 6/12/14 31 | * Time: 9:58 PM 32 | */ 33 | public class LuceneQueryVisitor extends LuceneSqlBaseVisitor { 34 | 35 | @Override 36 | public LuceneQueryAssembler visitFrom_stmt(@NotNull LuceneSqlParser.From_stmtContext ctx) { 37 | return super.visitFrom_stmt(ctx); 38 | } 39 | 40 | @Override 41 | public LuceneQueryAssembler visitWhere_stmt(@NotNull LuceneSqlParser.Where_stmtContext ctx) { 42 | return super.visitWhere_stmt(ctx); 43 | } 44 | 45 | @Override 46 | public LuceneQueryAssembler visitSelect_stmt(@NotNull LuceneSqlParser.Select_stmtContext ctx) { 47 | return super.visitSelect_stmt(ctx); 48 | } 49 | 50 | @Override 51 | public LuceneQueryAssembler visitQuery(@NotNull LuceneSqlParser.QueryContext ctx) { 52 | return super.visitQuery(ctx); 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/QueryParseResults.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import com.google.common.base.CharMatcher; 25 | import com.google.common.collect.Sets; 26 | import org.apache.lucene.queries.BooleanFilter; 27 | import org.apache.lucene.queries.FilterClause; 28 | import org.apache.lucene.search.BooleanClause; 29 | import org.apache.lucene.search.BooleanQuery; 30 | import org.apache.lucene.search.MatchAllDocsQuery; 31 | 32 | import java.util.Arrays; 33 | import java.util.HashSet; 34 | import java.util.List; 35 | import java.util.Set; 36 | import java.util.function.Predicate; 37 | 38 | /** 39 | * User: Bill Bejeck 40 | * Date: 2/18/15 41 | * Time: 10:38 PM 42 | */ 43 | public class QueryParseResults { 44 | 45 | private String indexPath; 46 | private Set selectFields = new HashSet<>(); 47 | private BooleanQuery booleanQuery; 48 | private BooleanFilter booleanFilter; 49 | private int limit; 50 | 51 | 52 | private QueryParseResults(Builder builder) { 53 | indexPath = builder.indexPath; 54 | selectFields = builder.selectFields; 55 | booleanQuery = builder.booleanQuery; 56 | booleanFilter = builder.booleanFilter; 57 | limit = builder.limit; 58 | } 59 | 60 | public String getIndexPath() { 61 | return indexPath; 62 | } 63 | 64 | public Set getSelectFields() { 65 | return selectFields; 66 | } 67 | 68 | public BooleanQuery getBooleanQuery() { 69 | return booleanQuery; 70 | } 71 | 72 | public BooleanFilter getBooleanFilter() { 73 | return booleanFilter; 74 | } 75 | 76 | public int getLimit() { 77 | return limit; 78 | } 79 | 80 | public static Builder newBuilder() { 81 | return new Builder(); 82 | } 83 | 84 | public static Builder newBuilder(QueryParseResults copy) { 85 | Builder builder = new Builder(); 86 | builder.indexPath = copy.indexPath; 87 | builder.selectFields = copy.selectFields; 88 | builder.booleanQuery = copy.booleanQuery; 89 | builder.booleanFilter = copy.booleanFilter; 90 | builder.limit = copy.limit; 91 | return builder; 92 | } 93 | 94 | 95 | public static final class Builder implements LuceneQueryFunctions { 96 | private String indexPath; 97 | private Set selectFields = new HashSet<>(); 98 | private List filterClausedList; 99 | private BooleanQuery booleanQuery; 100 | private BooleanFilter booleanFilter; 101 | private int limit; 102 | private CharMatcher singleQuoteMatcher = CharMatcher.is('\''); 103 | 104 | private Builder() { 105 | } 106 | 107 | public Builder withIndexPath(String indexPath) { 108 | if (indexPath != null) { 109 | this.indexPath = singleQuoteMatcher.removeFrom(indexPath); 110 | } 111 | return this; 112 | } 113 | 114 | public Builder withSelectFields(Set selectFields) { 115 | this.selectFields = Sets.newHashSet(selectFields); 116 | return this; 117 | } 118 | 119 | public Builder withBooleanQuery(BooleanQuery booleanQuery) { 120 | this.booleanQuery = booleanQuery; 121 | return this; 122 | } 123 | 124 | public Builder withBooleanFilter(BooleanFilter booleanFilter) { 125 | this.booleanFilter = booleanFilter; 126 | return this; 127 | } 128 | 129 | public Builder withLimit(int limit) { 130 | this.limit = limit; 131 | return this; 132 | } 133 | 134 | public QueryParseResults build() { 135 | if(isSingleMustNotQuery.test(booleanQuery)){ 136 | BooleanClause extractedClause = extractBooleanClause.apply(booleanQuery); 137 | List booleanClauseList = Arrays.asList(toMustBooleanClause.apply(new MatchAllDocsQuery()), extractedClause); 138 | booleanQuery = toBooleanQuery.apply(booleanClauseList); 139 | } 140 | return new QueryParseResults(this); 141 | } 142 | 143 | public Builder withFilterClausesList(List filterClausesList) { 144 | this.filterClausedList = filterClausesList; 145 | return this; 146 | } 147 | 148 | public Builder withBooleanClausesList(List booleanClausesList) { 149 | this.booleanQuery = toBooleanQuery.apply(booleanClausesList); 150 | return this; 151 | } 152 | 153 | private Predicate isSingleMustNotQuery = bq -> bq.clauses().size()==1 && bq.getClauses()[0].getOccur() == BooleanClause.Occur.MUST_NOT; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/QueryType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import com.google.common.base.Splitter; 25 | import org.apache.lucene.index.Term; 26 | import org.apache.lucene.search.*; 27 | 28 | import java.util.List; 29 | import java.util.function.Function; 30 | import java.util.function.Predicate; 31 | import java.util.stream.Collectors; 32 | import java.util.stream.Stream; 33 | 34 | /** 35 | * User: Bill Bejeck 36 | * Date: 9/22/14 37 | * Time: 11:23 PM 38 | */ 39 | public enum QueryType implements LuceneQueryFunctions, LuceneAnalyzingFunctions { 40 | 41 | TERM { 42 | @Override 43 | Query query(String field, String value) { 44 | 45 | if(value.matches("\\d+")){ 46 | return INTEGER_RANGE.query(field,value+":"+value); 47 | } 48 | 49 | Term t = createTerm.apply(field, lettersNumbersTrimLowerCase.apply(value)); 50 | return toQuery.apply(t, TermQuery.class); 51 | } 52 | }, 53 | 54 | REGEXP { 55 | @Override 56 | Query query(String field, String value) { 57 | //TODO add analyzing for regexp 58 | Term t = createTerm.apply(field, value); 59 | return toQuery.apply(t, RegexpQuery.class); 60 | } 61 | }, 62 | 63 | WILDCARD { 64 | @Override 65 | Query query(String field, String value) { 66 | String formatted = wildCardPrefixFormatter.apply(value); 67 | Term t = createTerm.apply(field, formatted); 68 | Class wildCardOrPrefixClass = getWildcardOrPrefixClass.apply(formatted); 69 | return toQuery.apply(t, wildCardOrPrefixClass); 70 | } 71 | }, 72 | 73 | PHRASE { 74 | @Override 75 | Query query(String field, String value) { 76 | return toPhraseQuery.apply(field, phraseFormatter.apply(value)); 77 | } 78 | }, 79 | 80 | BOOLEAN_OR_LIST { 81 | @Override 82 | Query query(String field, String value) { 83 | Function toTerm = termFunction.apply(field); 84 | List booleanClauseList = toStreamFromDelimitedValue.apply(value).map(lettersNumbersTrimLowerCase) 85 | .map(toTerm) 86 | .map(toTermQuery) 87 | .map(toOrBooleanClause) 88 | .collect(Collectors.toList()); 89 | return toBooleanQuery.apply(booleanClauseList); 90 | } 91 | }, 92 | 93 | BOOLEAN_PHRASE_LIST { 94 | @Override 95 | Query query(String field, String value) { 96 | List phraseValues = toStreamFromDelimitedValue.apply(value).filter(matchesPhrase).collect(Collectors.toList()); 97 | List termValues = toStreamFromDelimitedValue.apply(value).filter(notPhrase).collect(Collectors.toList()); 98 | 99 | List phraseQueries = phraseValues.stream().map(p -> toPhraseQuery.apply(field, phraseFormatter.apply(p))) 100 | .map(toOrBooleanClause) 101 | .collect(Collectors.toList()); 102 | Function toTerm = termFunction.apply(field); 103 | 104 | List termQueries = termValues.stream().map(lettersNumbersTrimLowerCase) 105 | .map(toTerm) 106 | .map(toTermQuery) 107 | .map(toOrBooleanClause) 108 | .collect(Collectors.toList()); 109 | phraseQueries.addAll(termQueries); 110 | return toBooleanQuery.apply(phraseQueries); 111 | } 112 | }, 113 | 114 | TERM_RANGE { 115 | @Override 116 | Query query(String field, String value) { 117 | List terms = toStreamFromDelimitedValue.apply(value).map(lettersNumbersTrimLowerCase).collect(Collectors.toList()); 118 | String lower = terms.get(0); 119 | String upper = terms.get(1); 120 | return TermRangeQuery.newStringRange(field, lower, upper, true, true); 121 | } 122 | }, 123 | 124 | INTEGER_RANGE { 125 | @Override 126 | Query query(String field, String value) { 127 | List terms = toStreamFromDelimitedValue.apply(value).map(lettersNumbersTrimLowerCase).map(Integer::decode).collect(Collectors.toList()); 128 | Integer lower = terms.get(0); 129 | Integer upper = terms.get(1); 130 | return NumericRangeQuery.newIntRange(field, lower, upper, true, true); 131 | } 132 | 133 | 134 | }, 135 | 136 | TERM_RANGE_UNBOUNDED { 137 | @Override 138 | Query query(String field, String value) { 139 | List terms = toStreamFromDelimitedValue.apply(value).map(lettersNumbersTrimLowerCase).collect(Collectors.toList()); 140 | String lower = (terms.get(0).equals(UNBOUNDED)) ? null : terms.get(0); 141 | String upper = (terms.get(1).equals(UNBOUNDED)) ? null : terms.get(1); 142 | boolean included = Boolean.valueOf(terms.get(2)); 143 | boolean includeUpper = lower == null && included; 144 | boolean includeLower = upper == null && included; 145 | return TermRangeQuery.newStringRange(field, lower, upper, includeLower, includeUpper); 146 | } 147 | }, 148 | 149 | INTEGER_RANGE_UNBOUNDED { 150 | @Override 151 | Query query(String field, String value) { 152 | List terms = toStreamFromDelimitedValue.apply(value).map(lettersNumbersTrimLowerCase).collect(Collectors.toList()); 153 | Integer lower = (terms.get(0).equals(UNBOUNDED)) ? null : Integer.decode(terms.get(0)); 154 | Integer upper = (terms.get(1).equals(UNBOUNDED)) ? null : Integer.decode(terms.get(1)); 155 | boolean included = Boolean.valueOf(terms.get(2)); 156 | boolean includeUpper = lower == null && included; 157 | boolean includeLower = upper == null && included; 158 | return NumericRangeQuery.newIntRange(field, lower, upper, includeLower, includeUpper); 159 | } 160 | }; 161 | 162 | 163 | abstract Query query(String field, String value); 164 | 165 | private static Function>> setDelimiter = d -> s -> Splitter.on(d).splitToList(s).stream(); 166 | private static Function> toStreamFromDelimitedValue = setDelimiter.apply(":"); 167 | private static Function phraseFormatter = removeMultipleSpace.andThen(lowerCase).andThen(lettersNumbersWhitespace).andThen(trim); 168 | private static Function wildCardPrefixFormatter = lettersNumbersWildcard.andThen(lowerCase); 169 | private static Predicate isPrefix = s -> s.indexOf('?') < 0 && s.endsWith("*"); 170 | private static Function, Function>> getCorrectClass = p -> s -> p.test(s) ? PrefixQuery.class : WildcardQuery.class; 171 | private static Function> getWildcardOrPrefixClass = getCorrectClass.apply(isPrefix); 172 | private static Predicate matchesPhrase = s -> s.matches("(['A-Za-z0-9]+\\s['A-Za-z0-9]+)+"); 173 | private static Predicate notPhrase = matchesPhrase.negate(); 174 | public static final String UNBOUNDED = "unbounded"; 175 | 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/lucene/Searcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import bbejeck.sql.antlr.LuceneQueryParser; 25 | import bbejeck.sql.util.ThrowingFunction; 26 | import com.google.common.base.Preconditions; 27 | import com.google.common.collect.ImmutableList; 28 | import com.google.common.collect.ImmutableMap; 29 | import org.apache.lucene.document.Document; 30 | import org.apache.lucene.index.DirectoryReader; 31 | import org.apache.lucene.index.IndexableField; 32 | import org.apache.lucene.search.IndexSearcher; 33 | import org.apache.lucene.search.ScoreDoc; 34 | import org.apache.lucene.search.TopDocs; 35 | import org.apache.lucene.store.Directory; 36 | import org.apache.lucene.store.FSDirectory; 37 | 38 | import java.io.IOException; 39 | import java.nio.file.Path; 40 | import java.nio.file.Paths; 41 | import java.util.List; 42 | import java.util.Map; 43 | import java.util.Set; 44 | import java.util.function.Function; 45 | import java.util.stream.Collectors; 46 | import java.util.stream.Stream; 47 | 48 | /** 49 | * User: Bill Bejeck 50 | * Date: 3/8/15 51 | * Time: 12:15 PM 52 | */ 53 | public class Searcher { 54 | 55 | private volatile IndexSearcher indexSearcher; 56 | private static final int DEFAULT_LIMIT = 10000; 57 | private static final Object lock = new Object(); 58 | 59 | private ThrowingFunction createPath = Paths::get; 60 | private ThrowingFunction createDirectory = FSDirectory::open; 61 | private ThrowingFunction createDirectoryReader = DirectoryReader::open; 62 | private ThrowingFunction openIndexSearcher = IndexSearcher::new; 63 | private ThrowingFunction fromDirectoryToIndexSearcher = createDirectoryReader.andThen(openIndexSearcher); 64 | private ThrowingFunction createIndexSearcherFromStringPath = createPath.andThen(createDirectory).andThen(createDirectoryReader).andThen(openIndexSearcher); 65 | private ThrowingFunction createIndexSearcherFromPath = createDirectory.andThen(createDirectoryReader).andThen(openIndexSearcher); 66 | 67 | private Function, Function>> getSearchDocsWithSelectedFields = fields -> searcher -> scoreDoc -> searcher.doc(scoreDoc.doc, fields); 68 | private Function> getSearchDocsWithAllFields = searcher -> scoreDoc -> searcher.doc(scoreDoc.doc); 69 | 70 | 71 | private Function, ImmutableMap> loadFieldIntoHashMap = list -> { 72 | ImmutableMap.Builder mapBuilder = ImmutableMap.builder(); 73 | list.forEach(field -> { 74 | Object value = (field.numericValue()!=null) ? field.numericValue() : field.stringValue(); 75 | mapBuilder.put(field.name(), value); 76 | }); 77 | return mapBuilder.build(); 78 | }; 79 | 80 | 81 | public Searcher() { 82 | } 83 | 84 | public Searcher(String indexPath){ 85 | Preconditions.checkArgument(indexPath != null && !indexPath.trim().isEmpty(), "Index Path is can't be null or empty"); 86 | this.indexSearcher = createIndexSearcherFromStringPath.apply(indexPath); 87 | } 88 | 89 | public Searcher(Path indexPath){ 90 | Preconditions.checkNotNull(indexPath,"Index Path can't be null"); 91 | this.indexSearcher = createIndexSearcherFromPath.apply(indexPath); 92 | } 93 | 94 | public Searcher(Directory directory) { 95 | Preconditions.checkNotNull(directory,"Directory can't be null"); 96 | this.indexSearcher = fromDirectoryToIndexSearcher.apply(directory); 97 | } 98 | 99 | public List> search(String query) throws IOException { 100 | 101 | QueryParseResults parseResults = LuceneQueryParser.parseQuery(query); 102 | 103 | if ( indexSearcher == null ) { 104 | synchronized (lock) { 105 | if( indexSearcher == null ) { 106 | indexSearcher = createIndexSearcherFromStringPath.apply(parseResults.getIndexPath()); 107 | } 108 | } 109 | } 110 | 111 | int maxResults = parseResults.getLimit() == 0 ? DEFAULT_LIMIT : parseResults.getLimit(); 112 | 113 | TopDocs topDocs = indexSearcher.search(parseResults.getBooleanQuery(), maxResults); 114 | Set fields = parseResults.getSelectFields(); 115 | ThrowingFunction retrieveDocFunction; 116 | 117 | if (fields.isEmpty()) { 118 | retrieveDocFunction = getSearchDocsWithAllFields.apply(indexSearcher); 119 | } else { 120 | retrieveDocFunction = getSearchDocsWithSelectedFields.apply(fields).apply(indexSearcher); 121 | 122 | } 123 | 124 | 125 | List> resultsListMutable = Stream.of(topDocs.scoreDocs).map(retrieveDocFunction) 126 | .map(Document::getFields) 127 | .map(loadFieldIntoHashMap) 128 | .collect(Collectors.toList()); 129 | 130 | return new ImmutableList.Builder>().addAll(resultsListMutable).build(); 131 | 132 | } 133 | 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/util/Collectors.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.util; 23 | 24 | import java.util.function.BiConsumer; 25 | import java.util.function.BinaryOperator; 26 | import java.util.function.Supplier; 27 | import java.util.stream.Collector; 28 | 29 | /** 30 | * User: Bill Bejeck 31 | * Date: 10/12/14 32 | * Time: 10:40 PM 33 | */ 34 | public class Collectors { 35 | private static final BinaryOperator noopCombiner = (l,r)->{throw new RuntimeException("Parallel execution not supported");}; 36 | 37 | @SuppressWarnings("unchecked") 38 | public static Collector nonParallelCollect(Supplier container, BiConsumer accumulator){ 39 | return Collector.of(container,accumulator, noopCombiner); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/util/Tester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.util; 23 | 24 | import java.util.function.Predicate; 25 | 26 | /** 27 | * User: Bill Bejeck 28 | * Date: 3/12/15 29 | * Time: 8:25 AM 30 | */ 31 | public class Tester { 32 | 33 | public static void main(String[] args) { 34 | 35 | 36 | Predicate matchesPhrase = s -> s.matches("([A-Za-z0-9]+\\s[A-Za-z0-9]+)+"); 37 | Predicate notPhrase = matchesPhrase.negate(); 38 | 39 | String s = "foo bar"; 40 | System.out.println(matchesPhrase.test(s)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/util/ThrowingBiFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.util; 23 | 24 | import java.util.function.BiFunction; 25 | 26 | /** 27 | * User: Bill Bejeck 28 | * Date: 3/11/15 29 | * Time: 11:07 PM 30 | */ 31 | @FunctionalInterface 32 | public interface ThrowingBiFunction extends BiFunction { 33 | 34 | @Override 35 | default R apply(T t, U u) { 36 | try { 37 | return throwsApply(t, u); 38 | } catch (Exception e) { 39 | throw new RuntimeException(e); 40 | } 41 | } 42 | 43 | 44 | R throwsApply(T t, U u) throws Exception; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/bbejeck/sql/util/ThrowingFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.util; 23 | 24 | import java.util.Objects; 25 | import java.util.function.Function; 26 | 27 | /** 28 | * User: Bill Bejeck 29 | * Date: 3/8/15 30 | * Time: 11:14 PM 31 | */ 32 | 33 | @FunctionalInterface 34 | public interface ThrowingFunction extends Function { 35 | 36 | @Override 37 | default R apply(T t){ 38 | try{ 39 | return applyThrows(t); 40 | }catch (Exception e){ 41 | throw new RuntimeException(e); 42 | } 43 | } 44 | 45 | default ThrowingFunction andThen(ThrowingFunction after){ 46 | Objects.requireNonNull(after); 47 | try{ 48 | return (T t) -> after.apply(apply(t)); 49 | }catch (Exception e){ 50 | throw new RuntimeException(e); 51 | } 52 | } 53 | 54 | default ThrowingFunction compose(ThrowingFunction before) { 55 | Objects.requireNonNull(before); 56 | try { 57 | return (V v) -> apply(before.apply(v)); 58 | }catch (Exception e){ 59 | throw new RuntimeException(e); 60 | } 61 | } 62 | 63 | R applyThrows(T t) throws Exception; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/LuceneQueryFunctionsTest.java: -------------------------------------------------------------------------------- 1 | package bbejeck.sql.lucene; 2 | 3 | import org.apache.lucene.index.Term; 4 | import org.apache.lucene.search.BooleanClause; 5 | import org.apache.lucene.search.PhraseQuery; 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.is; 9 | import static org.junit.Assert.assertThat; 10 | import static bbejeck.sql.lucene.LuceneQueryFunctions.*; 11 | 12 | public class LuceneQueryFunctionsTest { 13 | 14 | 15 | @Test 16 | public void testBuildPhraseQuery() { 17 | 18 | String field = "testField"; 19 | String text = "Foo Bar Baz"; 20 | 21 | PhraseQuery pq = LuceneQueryFunctions.toPhraseQuery.apply(field,text); 22 | Term[] terms = pq.getTerms(); 23 | assertThat(terms[0].field(),is(field)); 24 | assertThat(terms[0].text(),is("Foo")); 25 | assertThat(terms[1].field(),is(field)); 26 | assertThat(terms[1].text(),is("Bar")); 27 | assertThat(terms[2].field(),is(field)); 28 | assertThat(terms[2].text(),is("Baz")); 29 | 30 | } 31 | 32 | @Test 33 | public void testBuildTermQuery() { 34 | String field = "testField"; 35 | String text = "Foo Bar Baz"; 36 | BooleanClause clause = toBooleanClause.apply(field,text).apply(QueryType.TERM).apply(BooleanClause.Occur.MUST); 37 | 38 | } 39 | 40 | 41 | 42 | } -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/LuceneQueryParsingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import bbejeck.sql.antlr.LuceneQueryParser; 25 | import org.apache.lucene.index.Term; 26 | import org.apache.lucene.search.*; 27 | import org.junit.Test; 28 | 29 | import static org.hamcrest.CoreMatchers.is; 30 | import static org.hamcrest.CoreMatchers.nullValue; 31 | import static org.junit.Assert.assertArrayEquals; 32 | import static org.junit.Assert.assertThat; 33 | 34 | /** 35 | * User: Bill Bejeck 36 | * Date: 10/9/14 37 | * Time: 11:12 PM 38 | */ 39 | public class LuceneQueryParsingTest { 40 | 41 | 42 | @Test 43 | public void test_parse_term_and_phrase_query() { 44 | String query = "Select name,address from '/path/to/index/' where first_name='Beth' and last_name='Bejeck' or type='Big Cutie '"; 45 | BooleanQuery booleanQuery = parseQuery(query); 46 | BooleanClause[] clauses = booleanQuery.getClauses(); 47 | assertThat(clauses.length, is(3)); 48 | assertThat(clauses[0].getOccur(), is(BooleanClause.Occur.MUST)); 49 | assertThat(clauses[1].getOccur(), is(BooleanClause.Occur.MUST)); 50 | assertThat(clauses[2].getOccur(), is(BooleanClause.Occur.SHOULD)); 51 | 52 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 53 | assertThat(termQuery.getTerm().field(), is("first_name")); 54 | assertThat(termQuery.getTerm().text(), is("beth")); 55 | 56 | termQuery = (TermQuery) clauses[1].getQuery(); 57 | assertThat(termQuery.getTerm().field(), is("last_name")); 58 | assertThat(termQuery.getTerm().text(), is("bejeck")); 59 | 60 | assertThat(clauses[2].getQuery().getClass().isAssignableFrom(PhraseQuery.class), is(true)); 61 | assertThat(clauses[2].getOccur(), is(BooleanClause.Occur.SHOULD)); 62 | PhraseQuery phraseQuery = (PhraseQuery) clauses[2].getQuery(); 63 | assertArrayEquals(phraseQuery.getTerms(), new Term[]{new Term("type", "big"), new Term("type", "cutie")}); 64 | } 65 | 66 | @Test 67 | public void test_parse_term_correctly() { 68 | String query = "select foo from '/path/index/' where foo='Na,ME'"; 69 | BooleanQuery bq = parseQuery(query); 70 | BooleanClause[] clauses = bq.getClauses(); 71 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 72 | assertThat(termQuery.getTerm().field(), is("foo")); 73 | assertThat(termQuery.getTerm().text(), is("name")); 74 | 75 | } 76 | 77 | @Test 78 | public void test_parse_with_no_leading_slash() { 79 | String query = "select foo from 'path/index/' where foo='Na,ME'"; 80 | BooleanQuery bq = parseQuery(query); 81 | BooleanClause[] clauses = bq.getClauses(); 82 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 83 | assertThat(termQuery.getTerm().field(), is("foo")); 84 | assertThat(termQuery.getTerm().text(), is("name")); 85 | 86 | } 87 | 88 | @Test 89 | public void test_parse_regex_query() { 90 | String query = "Select foo from '/path/index/' where foo matches('[Bb].*[hH]?')"; 91 | BooleanQuery bq = parseQuery(query); 92 | BooleanClause[] clauses = bq.getClauses(); 93 | RegexpQuery regexpQuery = (RegexpQuery) clauses[0].getQuery(); 94 | assertThat(regexpQuery.getField(), is("foo")); 95 | // assertThat(regexpQuery.getTerm().text(),is("name")); 96 | } 97 | 98 | @Test 99 | public void test_parse_between_query() { 100 | String query = "Select foo from '/path/index/' where foo between 'Beth' and 'Elizabeth'"; 101 | BooleanQuery bq = parseQuery(query); 102 | BooleanClause[] clauses = bq.getClauses(); 103 | TermRangeQuery termRangeQuery = (TermRangeQuery) clauses[0].getQuery(); 104 | assertThat(termRangeQuery.getField(), is("foo")); 105 | assertThat(new String(termRangeQuery.getLowerTerm().bytes).trim(), is("beth")); 106 | assertThat(new String(termRangeQuery.getUpperTerm().bytes).trim(), is("elizabeth")); 107 | } 108 | 109 | @Test 110 | public void test_parse_between_integer_query() { 111 | String query = "Select foo from '/path/index/' where age between 33 and 48"; 112 | BooleanQuery bq = parseQuery(query); 113 | BooleanClause[] clauses = bq.getClauses(); 114 | NumericRangeQuery numericRangeQuery = (NumericRangeQuery) clauses[0].getQuery(); 115 | assertThat(numericRangeQuery.getField(), is("age")); 116 | assertThat(numericRangeQuery.getMin().intValue(), is(33)); 117 | assertThat(numericRangeQuery.getMax().intValue(), is(48)); 118 | } 119 | 120 | @Test 121 | public void test_parse_between_integer_query_no_select_from() { 122 | String query = "where age between 33 and 48"; 123 | BooleanQuery bq = parseQuery(query); 124 | BooleanClause[] clauses = bq.getClauses(); 125 | NumericRangeQuery numericRangeQuery = (NumericRangeQuery) clauses[0].getQuery(); 126 | assertThat(numericRangeQuery.getField(), is("age")); 127 | assertThat(numericRangeQuery.getMin().intValue(), is(33)); 128 | assertThat(numericRangeQuery.getMax().intValue(), is(48)); 129 | } 130 | 131 | @Test 132 | public void test_parse_like_wildcard_query() { 133 | String query = "select foo from '/path/index/' where name like 'B?t?'"; 134 | BooleanQuery bq = parseQuery(query); 135 | BooleanClause[] clauses = bq.getClauses(); 136 | WildcardQuery wildcardQuery = (WildcardQuery) clauses[0].getQuery(); 137 | assertThat(wildcardQuery.getField(), is("name")); 138 | assertThat(wildcardQuery.getTerm().text(), is("b?t?")); 139 | } 140 | 141 | @Test 142 | public void test_parse_like_wildcard_query_with_asteric() { 143 | String query = "select foo from '/path/index/' where name like 'B*th'"; 144 | BooleanQuery bq = parseQuery(query); 145 | BooleanClause[] clauses = bq.getClauses(); 146 | WildcardQuery wildcardQuery = (WildcardQuery) clauses[0].getQuery(); 147 | assertThat(wildcardQuery.getField(), is("name")); 148 | assertThat(wildcardQuery.getTerm().text(), is("b*th")); 149 | } 150 | 151 | @Test 152 | public void test_parse_like_prefix_query() { 153 | String query = "select foo from '/path/index/' where name like 'Bet*'"; 154 | BooleanQuery bq = parseQuery(query); 155 | BooleanClause[] clauses = bq.getClauses(); 156 | PrefixQuery prefixQuery = (PrefixQuery) clauses[0].getQuery(); 157 | assertThat(prefixQuery.getField(), is("name")); 158 | assertThat(prefixQuery.getPrefix().text(), is("bet*")); 159 | } 160 | 161 | 162 | @Test 163 | public void test_parse_in_listquery() throws Exception { 164 | String query = "select foo from '/path/index/' where name='Beth' and score in (0, 50, 55)"; 165 | QueryParseResults qc = parseQueryAndFilter(query); 166 | BooleanClause[] clauses = qc.getBooleanQuery().getClauses(); 167 | assertThat(clauses.length,is(2)); 168 | 169 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 170 | assertThat(termQuery.getTerm().field(), is("name")); 171 | assertThat(termQuery.getTerm().text(), is("beth")); 172 | 173 | BooleanQuery booleanQuery = (BooleanQuery) clauses[1].getQuery(); 174 | assertThat(booleanQuery.clauses().size(),is(3)); 175 | 176 | clauses = booleanQuery.getClauses(); 177 | 178 | TermQuery termQuery1 = (TermQuery) clauses[0].getQuery(); 179 | assertThat(termQuery1.getTerm().field(), is("score")); 180 | assertThat(termQuery1.getTerm().text(), is("0")); 181 | 182 | TermQuery termQuery2 = (TermQuery) clauses[1].getQuery(); 183 | assertThat(termQuery2.getTerm().field(), is("score")); 184 | assertThat(termQuery2.getTerm().text(), is("50")); 185 | 186 | TermQuery termQuery3 = (TermQuery) clauses[2].getQuery(); 187 | assertThat(termQuery3.getTerm().field(), is("score")); 188 | assertThat(termQuery3.getTerm().text(), is("55")); 189 | 190 | } 191 | 192 | @Test 193 | public void test_parse_in_term_listquery() throws Exception { 194 | String query = "select foo from '/path/index/' where name='Beth' and score in ('0', '50', '55')"; 195 | QueryParseResults qc = parseQueryAndFilter(query); 196 | BooleanClause[] clauses = qc.getBooleanQuery().getClauses(); 197 | assertThat(clauses.length,is(2)); 198 | 199 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 200 | assertThat(termQuery.getTerm().field(), is("name")); 201 | assertThat(termQuery.getTerm().text(), is("beth")); 202 | 203 | BooleanQuery booleanQuery = (BooleanQuery) clauses[1].getQuery(); 204 | assertThat(booleanQuery.clauses().size(),is(3)); 205 | 206 | clauses = booleanQuery.getClauses(); 207 | 208 | TermQuery termQuery1 = (TermQuery) clauses[0].getQuery(); 209 | assertThat(termQuery1.getTerm().field(), is("score")); 210 | assertThat(termQuery1.getTerm().text(), is("0")); 211 | 212 | TermQuery termQuery2 = (TermQuery) clauses[1].getQuery(); 213 | assertThat(termQuery2.getTerm().field(), is("score")); 214 | assertThat(termQuery2.getTerm().text(), is("50")); 215 | 216 | TermQuery termQuery3 = (TermQuery) clauses[2].getQuery(); 217 | assertThat(termQuery3.getTerm().field(), is("score")); 218 | assertThat(termQuery3.getTerm().text(), is("55")); 219 | 220 | } 221 | 222 | @Test 223 | public void test_parse_nested_query() throws Exception{ 224 | String query = "select foo from 'D:/some/path/' where a='1' and (b='2' and c='3' and d='4')"; 225 | QueryParseResults qc = parseQueryAndFilter(query); 226 | BooleanClause[] clauses = qc.getBooleanQuery().getClauses(); 227 | assertThat(clauses.length,is(2)); 228 | 229 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 230 | assertThat(termQuery.getTerm().field(), is("a")); 231 | assertThat(termQuery.getTerm().text(), is("1")); 232 | 233 | BooleanQuery booleanQuery = (BooleanQuery) clauses[1].getQuery(); 234 | assertThat(booleanQuery.clauses().size(),is(3)); 235 | 236 | clauses = booleanQuery.getClauses(); 237 | 238 | TermQuery termQuery1 = (TermQuery) clauses[0].getQuery(); 239 | assertThat(termQuery1.getTerm().field(), is("b")); 240 | assertThat(termQuery1.getTerm().text(), is("2")); 241 | 242 | TermQuery termQuery2 = (TermQuery) clauses[1].getQuery(); 243 | assertThat(termQuery2.getTerm().field(), is("c")); 244 | assertThat(termQuery2.getTerm().text(), is("3")); 245 | 246 | TermQuery termQuery3 = (TermQuery) clauses[2].getQuery(); 247 | assertThat(termQuery3.getTerm().field(), is("d")); 248 | assertThat(termQuery3.getTerm().text(), is("4")); 249 | } 250 | 251 | @Test 252 | public void test_parse_deeper_nested_query() throws Exception{ 253 | String query = "select foo from '/some/path/' where a='1' and (b='2' and (c='3' and (d='4' and e='5')))"; 254 | QueryParseResults qc = parseQueryAndFilter(query); 255 | //Overall query 256 | BooleanClause[] clauses = qc.getBooleanQuery().getClauses(); 257 | assertThat(clauses.length,is(2)); 258 | 259 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 260 | assertThat(termQuery.getTerm().field(), is("a")); 261 | assertThat(termQuery.getTerm().text(), is("1")); 262 | 263 | BooleanQuery booleanQuery = (BooleanQuery) clauses[1].getQuery(); 264 | assertThat(booleanQuery.clauses().size(),is(2)); 265 | 266 | //First nesting 267 | clauses = booleanQuery.getClauses(); 268 | 269 | TermQuery termQuery1 = (TermQuery) clauses[0].getQuery(); 270 | assertThat(termQuery1.getTerm().field(), is("b")); 271 | assertThat(termQuery1.getTerm().text(), is("2")); 272 | 273 | BooleanQuery booleanQuery1 = (BooleanQuery) clauses[1].getQuery(); 274 | assertThat(booleanQuery1.clauses().size(),is(2)); 275 | 276 | //Second nesting 277 | clauses = booleanQuery1.getClauses(); 278 | 279 | TermQuery termQuery2 = (TermQuery) clauses[0].getQuery(); 280 | assertThat(termQuery2.getTerm().field(), is("c")); 281 | assertThat(termQuery2.getTerm().text(), is("3")); 282 | 283 | BooleanQuery booleanQuery2 = (BooleanQuery) clauses[1].getQuery(); 284 | assertThat(booleanQuery2.clauses().size(),is(2)); 285 | 286 | //Third nesting 287 | clauses = booleanQuery2.getClauses(); 288 | 289 | TermQuery termQuery3 = (TermQuery) clauses[0].getQuery(); 290 | assertThat(termQuery3.getTerm().field(), is("d")); 291 | assertThat(termQuery3.getTerm().text(), is("4")); 292 | 293 | TermQuery termQuery4 = (TermQuery) clauses[1].getQuery(); 294 | assertThat(termQuery4.getTerm().field(), is("e")); 295 | assertThat(termQuery4.getTerm().text(), is("5")); 296 | } 297 | 298 | @Test 299 | public void test_parse_deeper_nested_with_in_term_clause_query() throws Exception{ 300 | String query = "select foo from '/some/path/' where a='1' and (b='2' and (c='3' and (d='4' and e in (5,6,7))))"; 301 | QueryParseResults qc = parseQueryAndFilter(query); 302 | //Overall query 303 | BooleanClause[] clauses = qc.getBooleanQuery().getClauses(); 304 | assertThat(clauses.length,is(2)); 305 | 306 | TermQuery termQuery = (TermQuery) clauses[0].getQuery(); 307 | assertThat(termQuery.getTerm().field(), is("a")); 308 | assertThat(termQuery.getTerm().text(), is("1")); 309 | 310 | BooleanQuery booleanQuery = (BooleanQuery) clauses[1].getQuery(); 311 | assertThat(booleanQuery.clauses().size(),is(2)); 312 | 313 | //First nesting 314 | clauses = booleanQuery.getClauses(); 315 | 316 | TermQuery termQuery1 = (TermQuery) clauses[0].getQuery(); 317 | assertThat(termQuery1.getTerm().field(), is("b")); 318 | assertThat(termQuery1.getTerm().text(), is("2")); 319 | 320 | BooleanQuery booleanQuery1 = (BooleanQuery) clauses[1].getQuery(); 321 | assertThat(booleanQuery1.clauses().size(),is(2)); 322 | 323 | //Second nesting 324 | clauses = booleanQuery1.getClauses(); 325 | 326 | TermQuery termQuery2 = (TermQuery) clauses[0].getQuery(); 327 | assertThat(termQuery2.getTerm().field(), is("c")); 328 | assertThat(termQuery2.getTerm().text(), is("3")); 329 | 330 | BooleanQuery booleanQuery2 = (BooleanQuery) clauses[1].getQuery(); 331 | assertThat(booleanQuery2.clauses().size(),is(2)); 332 | 333 | //Third nesting 334 | clauses = booleanQuery2.getClauses(); 335 | 336 | TermQuery termQuery3 = (TermQuery) clauses[0].getQuery(); 337 | assertThat(termQuery3.getTerm().field(), is("d")); 338 | assertThat(termQuery3.getTerm().text(), is("4")); 339 | 340 | BooleanQuery booleanQuery3 = (BooleanQuery) clauses[1].getQuery(); 341 | assertThat(booleanQuery3.clauses().size(),is(3)); 342 | 343 | clauses = booleanQuery3.getClauses(); 344 | 345 | TermQuery termQuery4 = (TermQuery) clauses[0].getQuery(); 346 | assertThat(termQuery4.getTerm().field(), is("e")); 347 | assertThat(termQuery4.getTerm().text(), is("5")); 348 | 349 | TermQuery termQuery5 = (TermQuery) clauses[1].getQuery(); 350 | assertThat(termQuery5.getTerm().field(), is("e")); 351 | assertThat(termQuery5.getTerm().text(), is("6")); 352 | 353 | TermQuery termQuery6 = (TermQuery) clauses[2].getQuery(); 354 | assertThat(termQuery6.getTerm().field(), is("e")); 355 | assertThat(termQuery6.getTerm().text(), is("7")); 356 | } 357 | 358 | @Test 359 | public void test_less_than_number(){ 360 | String query = "Select foo from '/index/path/' where age < 49"; 361 | BooleanQuery booleanQuery = parseQuery(query); 362 | BooleanClause[] clauses = booleanQuery.getClauses(); 363 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("NumericRangeQuery")); 364 | NumericRangeQuery numericRangeQuery = (NumericRangeQuery) clauses[0].getQuery(); 365 | assertThat(numericRangeQuery.getMin(), is(nullValue())); 366 | assertThat(numericRangeQuery.getMax(), is(49)); 367 | assertThat(numericRangeQuery.includesMax(),is(false)); 368 | } 369 | 370 | @Test 371 | public void test_less_than_equals_number(){ 372 | String query = "Select foo from '/index/path/' where age <= 49"; 373 | BooleanQuery booleanQuery = parseQuery(query); 374 | BooleanClause[] clauses = booleanQuery.getClauses(); 375 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("NumericRangeQuery")); 376 | NumericRangeQuery numericRangeQuery = (NumericRangeQuery) clauses[0].getQuery(); 377 | assertThat(numericRangeQuery.getMin(),is(nullValue())); 378 | assertThat(numericRangeQuery.getMax(),is(49)); 379 | assertThat(numericRangeQuery.includesMax(),is(true)); 380 | } 381 | 382 | @Test 383 | public void test_greater_than_number(){ 384 | String query = "Select foo from '/index/path/' where age > 49"; 385 | BooleanQuery booleanQuery = parseQuery(query); 386 | BooleanClause[] clauses = booleanQuery.getClauses(); 387 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("NumericRangeQuery")); 388 | NumericRangeQuery numericRangeQuery = (NumericRangeQuery) clauses[0].getQuery(); 389 | assertThat(numericRangeQuery.getMin(), is(49)); 390 | assertThat(numericRangeQuery.getMax(), is(nullValue())); 391 | assertThat(numericRangeQuery.includesMin(),is(false)); 392 | } 393 | 394 | @Test 395 | public void test_greater_than_equals_number(){ 396 | String query = "Select foo from '/index/path/' where age >= 49"; 397 | BooleanQuery booleanQuery = parseQuery(query); 398 | BooleanClause[] clauses = booleanQuery.getClauses(); 399 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("NumericRangeQuery")); 400 | NumericRangeQuery numericRangeQuery = (NumericRangeQuery) clauses[0].getQuery(); 401 | assertThat(numericRangeQuery.getMin(),is(49)); 402 | assertThat(numericRangeQuery.getMax(),is(nullValue())); 403 | assertThat(numericRangeQuery.includesMin(),is(true)); 404 | } 405 | 406 | @Test 407 | public void test_less_than_term(){ 408 | String query = "Select foo from '/index/path/' where age < '49'"; 409 | BooleanQuery booleanQuery = parseQuery(query); 410 | BooleanClause[] clauses = booleanQuery.getClauses(); 411 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("TermRangeQuery")); 412 | TermRangeQuery termRangeQuery = (TermRangeQuery) clauses[0].getQuery(); 413 | assertThat(termRangeQuery.getLowerTerm(), is(nullValue())); 414 | assertThat(termRangeQuery.getUpperTerm().utf8ToString(), is("49")); 415 | assertThat(termRangeQuery.includesUpper(),is(false)); 416 | } 417 | 418 | @Test 419 | public void test_less_than_equals_term(){ 420 | String query = "Select foo from '/index/path/' where age <= '49'"; 421 | BooleanQuery booleanQuery = parseQuery(query); 422 | BooleanClause[] clauses = booleanQuery.getClauses(); 423 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("TermRangeQuery")); 424 | TermRangeQuery termRangeQuery = (TermRangeQuery) clauses[0].getQuery(); 425 | assertThat(termRangeQuery.getLowerTerm(),is(nullValue())); 426 | assertThat(termRangeQuery.getUpperTerm().utf8ToString(),is("49")); 427 | assertThat(termRangeQuery.includesUpper(),is(true)); 428 | } 429 | 430 | @Test 431 | public void test_greater_than_term(){ 432 | String query = "Select foo from '/index/path/' where age > '49'"; 433 | BooleanQuery booleanQuery = parseQuery(query); 434 | BooleanClause[] clauses = booleanQuery.getClauses(); 435 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("TermRangeQuery")); 436 | TermRangeQuery termRangeQuery = (TermRangeQuery) clauses[0].getQuery(); 437 | assertThat(termRangeQuery.getLowerTerm().utf8ToString(), is("49")); 438 | assertThat(termRangeQuery.getUpperTerm(), is(nullValue())); 439 | assertThat(termRangeQuery.includesLower(),is(false)); 440 | } 441 | 442 | @Test 443 | public void test_greater_than_equals_term(){ 444 | String query = "Select foo from '/index/path/' where age >= '49'"; 445 | BooleanQuery booleanQuery = parseQuery(query); 446 | BooleanClause[] clauses = booleanQuery.getClauses(); 447 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("TermRangeQuery")); 448 | TermRangeQuery termRangeQuery = (TermRangeQuery) clauses[0].getQuery(); 449 | assertThat(termRangeQuery.getLowerTerm().utf8ToString(), is("49")); 450 | assertThat(termRangeQuery.getUpperTerm(), is(nullValue())); 451 | assertThat(termRangeQuery.includesLower(), is(true)); 452 | } 453 | 454 | @Test 455 | public void test_greater_than_equals_date(){ 456 | String query = "Select foo from '/index/path/' where date >= 2015/03/18"; 457 | BooleanQuery booleanQuery = parseQuery(query); 458 | BooleanClause[] clauses = booleanQuery.getClauses(); 459 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("TermRangeQuery")); 460 | TermRangeQuery termRangeQuery = (TermRangeQuery) clauses[0].getQuery(); 461 | assertThat(termRangeQuery.getLowerTerm().utf8ToString(), is("20150318")); 462 | assertThat(termRangeQuery.getUpperTerm(), is(nullValue())); 463 | assertThat(termRangeQuery.includesLower(), is(true)); 464 | } 465 | 466 | @Test 467 | public void test_greater_than_equals_date_dash_separators(){ 468 | String query = "Select foo from '/index/path/' where date >= 2015-03-18"; 469 | BooleanQuery booleanQuery = parseQuery(query); 470 | BooleanClause[] clauses = booleanQuery.getClauses(); 471 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("TermRangeQuery")); 472 | TermRangeQuery termRangeQuery = (TermRangeQuery) clauses[0].getQuery(); 473 | assertThat(termRangeQuery.getLowerTerm().utf8ToString(), is("20150318")); 474 | assertThat(termRangeQuery.getUpperTerm(), is(nullValue())); 475 | assertThat(termRangeQuery.includesLower(), is(true)); 476 | } 477 | 478 | @Test 479 | public void test_search_number_field() throws Exception { 480 | String query = "Select age,city from '/path/to/index/' where first_name='john' and ageN=50"; 481 | BooleanQuery booleanQuery = parseQuery(query); 482 | BooleanClause[] clauses = booleanQuery.getClauses(); 483 | assertThat(clauses[0].getQuery().getClass().getSimpleName(),is("TermQuery")); 484 | assertThat(clauses[1].getQuery().getClass().getSimpleName(),is("NumericRangeQuery")); 485 | } 486 | 487 | 488 | 489 | private BooleanQuery parseQuery(String luceneQuery) { 490 | return LuceneQueryParser.parseToBooleanQuery(luceneQuery); 491 | } 492 | 493 | private QueryParseResults parseQueryAndFilter(String luceneQuery){ 494 | return LuceneQueryParser.parseQuery(luceneQuery); 495 | } 496 | 497 | 498 | } 499 | -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/LuceneQuerySearchTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import bbejeck.sql.antlr.LuceneQueryParser; 25 | import org.apache.lucene.search.*; 26 | import org.junit.Test; 27 | 28 | import static org.hamcrest.CoreMatchers.is; 29 | import static org.junit.Assert.assertThat; 30 | 31 | /** 32 | * User: Bill Bejeck 33 | * Date: 1/20/15 34 | * Time: 9:48 PM 35 | */ 36 | public class LuceneQuerySearchTest extends LuceneSqlSearchBase { 37 | 38 | 39 | public LuceneQuerySearchTest() throws Exception { 40 | init(); 41 | index_values_from_file("src/test/small_values.csv"); 42 | doneAdding(); 43 | openSearcher(); 44 | } 45 | 46 | @Test 47 | public void test_search_boolean_and_terms() throws Exception { 48 | String query = "Select name,address from '/path/to/index/' where first_name='beth' and last_name='bejeck'"; 49 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 50 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 51 | assertThat(scoreDocs.length, is(1)); 52 | } 53 | 54 | @Test 55 | public void test_search_between() throws Exception { 56 | String query = "Select first_name,last_name,address from '/path/to/index/' where first_name='john' and ageN between 30 and 40"; 57 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 58 | System.out.println(booleanQuery); 59 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 60 | assertThat(scoreDocs.length, is(3)); 61 | } 62 | 63 | @Test 64 | public void test_search_in_list() throws Exception { 65 | String query = "Select name,address from '/path/to/index/' where first_name='john' and city in ('Portsmith', 'Rockville')"; 66 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 67 | System.out.println(booleanQuery); 68 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 69 | assertThat(scoreDocs.length, is(3)); 70 | } 71 | 72 | @Test 73 | public void test_search_in_listII() throws Exception { 74 | String query = "Select name,address from '/path/to/index/' where first_name='john' and city in ('Portsmith', 'Rockville','Cleveland')"; 75 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 76 | System.out.println(booleanQuery); 77 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 78 | assertThat(scoreDocs.length, is(4)); 79 | } 80 | 81 | @Test 82 | public void test_search_not_in_list_nested_boolean() throws Exception { 83 | String query = "Select name,address from '/path/to/index/' where first_name='john' and not (city in ('Portsmith', 'Rockville','Cleveland'))"; 84 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 85 | System.out.println(booleanQuery); 86 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 87 | assertThat(scoreDocs.length, is(2)); 88 | } 89 | 90 | @Test 91 | public void test_search_not_in_list() throws Exception { 92 | String query = "Select name,address from '/path/to/index/' where first_name='john' and city not in ('Portsmith', 'Rockville','Cleveland')"; 93 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 94 | System.out.println(booleanQuery); 95 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 96 | assertThat(scoreDocs.length, is(2)); 97 | } 98 | 99 | @Test 100 | public void test_search_in_phrase_term_list() throws Exception { 101 | String query = "Select first_name from '/path/to/index/' where city in ('New York', 'Silver Spring','Bedrock')"; 102 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 103 | System.out.println(booleanQuery); 104 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 105 | assertThat(scoreDocs.length, is(4)); 106 | } 107 | 108 | @Test 109 | public void test_search_in_phrase_list() throws Exception { 110 | String query = "Select first_name from '/path/to/index/' where city in ('New York', 'Silver Spring')"; 111 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 112 | System.out.println(booleanQuery); 113 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 114 | assertThat(scoreDocs.length, is(2)); 115 | } 116 | 117 | @Test 118 | public void test_search_not_in_phrase_list() throws Exception { 119 | String query = "Select first_name from '/path/to/index/' where city not in ('New York', 'Silver Spring')"; 120 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 121 | System.out.println(booleanQuery); 122 | ScoreDoc[] scoreDocs = search(booleanQuery,100); 123 | assertThat(scoreDocs.length, is(10)); 124 | } 125 | 126 | @Test 127 | public void test_search_not_only_term_clause() throws Exception { 128 | String query = "Select first_name from '/path/to/index/' where first_name != 'Barny' "; 129 | BooleanQuery booleanQuery = LuceneQueryParser.parseToBooleanQuery(query); 130 | System.out.println(booleanQuery); 131 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 132 | assertThat(scoreDocs.length, is(11)); 133 | } 134 | 135 | @Test 136 | public void test_search_numbers_in_list() throws Exception { 137 | String query = "Select * from 'path/index/' where age in (31, 30, 50)"; 138 | BooleanQuery booleanQuery = LuceneQueryParser.parseToBooleanQuery(query); 139 | System.out.println(booleanQuery); 140 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 141 | assertThat(scoreDocs.length, is(3)); 142 | } 143 | 144 | @Test 145 | public void test_search_less_than() throws Exception { 146 | String query = "Select * from '/path/to/index/' where ageN < 40"; 147 | BooleanQuery booleanQuery = LuceneQueryParser.parseQuery(query).getBooleanQuery(); 148 | System.out.println(booleanQuery); 149 | ScoreDoc[] scoreDocs = search(booleanQuery, 100); 150 | assertThat(scoreDocs.length, is(4)); 151 | } 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | } 160 | -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/LuceneSqlFileSystemSearchBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import org.apache.lucene.index.DirectoryReader; 25 | import org.apache.lucene.index.IndexWriter; 26 | import org.apache.lucene.search.IndexSearcher; 27 | import org.apache.lucene.store.Directory; 28 | import org.apache.lucene.store.FSDirectory; 29 | 30 | import java.nio.file.Paths; 31 | 32 | /** 33 | * User: Bill Bejeck 34 | * Date: 3/25/15 35 | * Time: 10:08 PM 36 | */ 37 | public abstract class LuceneSqlFileSystemSearchBase extends LuceneSqlSearchBase { 38 | 39 | protected Directory fsDirectory; 40 | 41 | 42 | public void init(String path) throws Exception { 43 | fsDirectory = FSDirectory.open(Paths.get(path)); 44 | iwriter = new IndexWriter(fsDirectory, config); 45 | 46 | } 47 | 48 | @Override 49 | public void openSearcher() throws Exception { 50 | ireader = DirectoryReader.open(fsDirectory); 51 | isearcher = new IndexSearcher(ireader); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/LuceneSqlSearchBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import com.google.common.base.Splitter; 25 | import org.apache.lucene.analysis.Analyzer; 26 | import org.apache.lucene.analysis.standard.StandardAnalyzer; 27 | import org.apache.lucene.document.Document; 28 | import org.apache.lucene.document.Field; 29 | import org.apache.lucene.document.FieldType; 30 | import org.apache.lucene.document.IntField; 31 | import org.apache.lucene.index.DirectoryReader; 32 | import org.apache.lucene.index.IndexOptions; 33 | import org.apache.lucene.index.IndexWriter; 34 | import org.apache.lucene.index.IndexWriterConfig; 35 | import org.apache.lucene.search.Filter; 36 | import org.apache.lucene.search.IndexSearcher; 37 | import org.apache.lucene.search.Query; 38 | import org.apache.lucene.search.ScoreDoc; 39 | import org.apache.lucene.store.Directory; 40 | import org.apache.lucene.store.RAMDirectory; 41 | 42 | import java.io.IOException; 43 | import java.nio.file.Files; 44 | import java.nio.file.Path; 45 | import java.nio.file.Paths; 46 | import java.util.List; 47 | import java.util.function.Function; 48 | import java.util.function.Supplier; 49 | import java.util.stream.Collectors; 50 | 51 | /** 52 | * User: Bill Bejeck 53 | * Date: 10/13/14 54 | * Time: 11:11 PM 55 | */ 56 | public abstract class LuceneSqlSearchBase { 57 | 58 | protected Analyzer analyzer = new StandardAnalyzer(); 59 | protected Directory ramDirectory = new RAMDirectory(); 60 | protected IndexWriterConfig config = new IndexWriterConfig(analyzer); 61 | protected IndexWriter iwriter; 62 | protected DirectoryReader ireader; 63 | protected IndexSearcher isearcher; 64 | 65 | private Function> splitDelimited = line -> Splitter.on(",").splitToList(line); 66 | private Function> toFieldFunction = ft -> s -> new Field(s, "", ft); 67 | private com.google.common.base.Supplier documentSupplier = Document::new; 68 | 69 | private Supplier fieldTypeSupplier = () -> { 70 | FieldType fieldType = new FieldType(); 71 | fieldType.setStored(true); 72 | fieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS); 73 | return fieldType; 74 | }; 75 | 76 | private Function,Function,Document>> toFieldsToDocument = fields -> values -> { 77 | Document doc = documentSupplier.get(); 78 | int indx = 0; 79 | for (Field column : fields) { 80 | String val = values.get(indx++); 81 | if(val.matches("\\d+")){ 82 | int num = Integer.parseInt(val); 83 | IntField numberColumn = new IntField(column.name()+"N",num, Field.Store.YES); 84 | doc.add(numberColumn); 85 | } 86 | column.setStringValue(val); 87 | doc.add(column); 88 | } 89 | return doc; 90 | }; 91 | 92 | private Function toField = toFieldFunction.apply(fieldTypeSupplier.get()); 93 | 94 | 95 | 96 | public ScoreDoc[] search(Query query, int limit) throws Exception { 97 | if(ireader == null){ 98 | openSearcher(); 99 | } 100 | 101 | return isearcher.search(query,limit).scoreDocs; 102 | } 103 | 104 | public ScoreDoc[] search(Query query,Filter filter, int limit) throws Exception { 105 | if(ireader == null){ 106 | openSearcher(); 107 | } 108 | 109 | return isearcher.search(query,limit).scoreDocs; 110 | } 111 | 112 | public void init() throws Exception { 113 | iwriter = new IndexWriter(ramDirectory, config); 114 | } 115 | 116 | public void openSearcher() throws Exception { 117 | ireader = DirectoryReader.open(ramDirectory); 118 | isearcher = new IndexSearcher(ireader); 119 | } 120 | 121 | public void addDocumentToIndex(Document doc) { 122 | try { 123 | iwriter.addDocument(doc); 124 | } catch (IOException e) { 125 | throw new RuntimeException(e); 126 | } 127 | } 128 | 129 | public void doneAdding() throws Exception { 130 | iwriter.close(); 131 | } 132 | 133 | protected void index_values_from_file(String path) throws Exception { 134 | Path fakeNames = Paths.get(path); 135 | List lines = Files.readAllLines(fakeNames); 136 | List columnFields = splitDelimited.apply(lines.get(0)).stream().map(toField).collect(Collectors.toList()); 137 | lines.stream().skip(1).map(splitDelimited).map(toFieldsToDocument.apply(columnFields)).forEach(this::addDocumentToIndex); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/QueryTypeTest.java: -------------------------------------------------------------------------------- 1 | package bbejeck.sql.lucene; 2 | 3 | 4 | import org.apache.lucene.search.Query; 5 | import org.apache.lucene.search.RegexpQuery; 6 | import org.apache.lucene.search.TermQuery; 7 | import org.apache.lucene.search.WildcardQuery; 8 | import org.junit.Test; 9 | 10 | import static bbejeck.sql.lucene.QueryType.REGEXP; 11 | import static bbejeck.sql.lucene.QueryType.WILDCARD; 12 | import static org.junit.Assert.*; 13 | import static org.hamcrest.CoreMatchers.*; 14 | 15 | import static bbejeck.sql.lucene.QueryType.TERM; 16 | 17 | public class QueryTypeTest { 18 | 19 | private static final String FIELD = "foo"; 20 | private static final String TEXT = "bar"; 21 | 22 | @Test 23 | public void testTerm() { 24 | Query tq = TERM.query(FIELD,TEXT); 25 | assertThat(tq.getClass().getSimpleName(),is("TermQuery")); 26 | assertThat(((TermQuery)tq).getTerm().field(),is(FIELD)); 27 | assertThat(((TermQuery)tq).getTerm().text(),is(TEXT)); 28 | } 29 | 30 | @Test 31 | public void testRegex() { 32 | Query tq = REGEXP.query(FIELD,TEXT); 33 | assertThat(tq.getClass().getSimpleName(),is("RegexpQuery")); 34 | assertThat(((RegexpQuery)tq).getField(),is(FIELD)); 35 | } 36 | 37 | @Test 38 | public void testWildCard() { 39 | Query tq = WILDCARD.query(FIELD,TEXT); 40 | assertThat(tq.getClass().getSimpleName(),is("WildcardQuery")); 41 | assertThat(((WildcardQuery)tq).getTerm().field(),is(FIELD)); 42 | assertThat(((WildcardQuery)tq).getTerm().text(),is(TEXT)); 43 | } 44 | 45 | 46 | } -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/SearcherFileSystemIndexTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import org.junit.After; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | 28 | import java.io.File; 29 | import java.nio.file.Paths; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.stream.Stream; 33 | 34 | import static org.hamcrest.CoreMatchers.is; 35 | import static org.junit.Assert.assertThat; 36 | 37 | /** 38 | * User: Bill Bejeck 39 | * Date: 3/25/15 40 | * Time: 10:16 PM 41 | */ 42 | public class SearcherFileSystemIndexTest extends LuceneSqlFileSystemSearchBase { 43 | 44 | private String indexPath = "src/test/testindex"; 45 | 46 | @Before 47 | public void setup() throws Exception { 48 | init(indexPath); 49 | index_values_from_file("src/test/small_values.csv"); 50 | doneAdding(); 51 | } 52 | 53 | @After 54 | public void teardown() throws Exception { 55 | File file = new File(indexPath); 56 | Stream.of(file.listFiles()).forEach(File::delete); 57 | } 58 | 59 | 60 | @Test 61 | public void test_search_opening_index_from_query() throws Exception { 62 | Searcher searcher = new Searcher(); 63 | String query = "Select ageN,city from '"+indexPath+"/' where first_name='john' and ageN=50"; 64 | List> results = searcher.search(query); 65 | assertThat(results.size(), is(1)); 66 | Map resultMap = results.get(0); 67 | assertThat(resultMap.keySet().size(), is(2)); 68 | assertThat(resultMap.get("ageN"),is(50)); 69 | assertThat(resultMap.get("city"), is("Portsmith")); 70 | } 71 | 72 | @Test 73 | public void test_search_opening_path_provided() throws Exception { 74 | Searcher searcher = new Searcher(indexPath); 75 | String query = "Select ageN,city where first_name='john' and ageN=50"; 76 | List> results = searcher.search(query); 77 | assertThat(results.size(), is(1)); 78 | Map resultMap = results.get(0); 79 | assertThat(resultMap.keySet().size(), is(2)); 80 | assertThat(resultMap.get("ageN"),is(50)); 81 | assertThat(resultMap.get("city"), is("Portsmith")); 82 | } 83 | 84 | @Test 85 | public void test_search_opening_path_object_provided() throws Exception { 86 | Searcher searcher = new Searcher(Paths.get(indexPath)); 87 | String query = "Select ageN,city where first_name='john' and ageN=50"; 88 | List> results = searcher.search(query); 89 | assertThat(results.size(), is(1)); 90 | Map resultMap = results.get(0); 91 | assertThat(resultMap.keySet().size(), is(2)); 92 | assertThat(resultMap.get("ageN"),is(50)); 93 | assertThat(resultMap.get("city"), is("Portsmith")); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/bbejeck/sql/lucene/SearcherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * * 3 | * 4 | * 5 | * Copyright 2015 Bill Bejeck 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * 20 | */ 21 | 22 | package bbejeck.sql.lucene; 23 | 24 | import org.junit.Test; 25 | 26 | import java.util.List; 27 | import java.util.Map; 28 | 29 | import static org.junit.Assert.*; 30 | import static org.hamcrest.CoreMatchers.*; 31 | 32 | public class SearcherTest extends LuceneSqlSearchBase { 33 | 34 | private Searcher searcher; 35 | 36 | public SearcherTest() throws Exception{ 37 | init(); 38 | index_values_from_file("src/test/small_values.csv"); 39 | doneAdding(); 40 | searcher = new Searcher(ramDirectory); 41 | openSearcher(); 42 | } 43 | 44 | @Test 45 | public void test_search_single_map_in_list() throws Exception { 46 | String query = "Select age,city from '/path/to/index/' where first_name='john' and age='50'"; 47 | List> results = searcher.search(query); 48 | assertThat(results.size(),is(1)); 49 | Map resultMap = results.get(0); 50 | assertThat(resultMap.keySet().size(),is(2)); 51 | assertThat(resultMap.get("age"),is("50")); 52 | assertThat(resultMap.get("city"),is("Portsmith")); 53 | } 54 | 55 | @Test 56 | public void test_search_number_field() throws Exception { 57 | String query = "Select ageN,city from '/path/to/index/' where first_name='john' and ageN=50"; 58 | List> results = searcher.search(query); 59 | assertThat(results.size(),is(1)); 60 | Map resultMap = results.get(0); 61 | assertThat(resultMap.keySet().size(),is(2)); 62 | assertThat(resultMap.get("ageN"),is(50)); 63 | assertThat(resultMap.get("city"),is("Portsmith")); 64 | } 65 | 66 | @Test 67 | public void test_search_single_map_no_fields_specified() throws Exception { 68 | String query = "Select * from '/path/to/index/' where first_name='john' and age ='50'"; 69 | List> results = searcher.search(query); 70 | assertThat(results.size(),is(1)); 71 | Map resultMap = results.get(0); 72 | assertThat(resultMap.keySet().size(),is(5)); 73 | assertThat(resultMap.get("first_name"),is("John")); 74 | assertThat(resultMap.get("last_name"),is("Smith")); 75 | assertThat(resultMap.get("city"),is("Portsmith")); 76 | assertThat(resultMap.get("age"),is("50")); 77 | assertThat(resultMap.get("ageN"),is(50)); 78 | } 79 | 80 | @Test 81 | public void test_search_single_map_no_fields_specified_limit() throws Exception { 82 | String query = "Select * from '/path/to/index/' where first_name='john'"; 83 | List> results = searcher.search(query); 84 | assertThat(results.size(), is(6)); 85 | 86 | query = "Select * from '/path/to/index/' where first_name='john' limit 2"; 87 | results = searcher.search(query); 88 | assertThat(results.size(), is(2)); 89 | 90 | } 91 | } -------------------------------------------------------------------------------- /src/test/small_values.csv: -------------------------------------------------------------------------------- 1 | first_name,last_name,age,city 2 | Beth,Niemiec,31,Salisbury 3 | Beth,Bejeck,48,Boyds 4 | John,Smith,50,Portsmith 5 | John,Smith,30,Portsmith 6 | John,Smith,35,Cleveland 7 | John,Smith,35,Cincinatti 8 | John,Smith,43,Rockville 9 | John,Smith,44,New York 10 | Betty,Smith,45,Portsmith 11 | Beth,Smith,44,Silver Spring 12 | Fred,Flinstone,45,Bedrock 13 | Barny,Rubble,44,Bedrock --------------------------------------------------------------------------------