From caed55ef5eb1e06c8d52c5fa084517cc5f7ab9e8 Mon Sep 17 00:00:00 2001 From: Mark Harwood Date: Sun, 17 Feb 2008 22:32:58 +0000 Subject: [PATCH] Added thread-safety around use of core's QueryParser. Old XML parser constructors use a mode which will synchronize on use of the user-supplied QueryParser. New constructors offer alternative option of passing "defaultField" String which is used to create a new single-use QueryParser for each parse operation. git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@628568 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/lucene/xmlparser/CoreParser.java | 30 +++++++++++++++- .../xmlparser/CorePlusExtensionsParser.java | 24 +++++++++++-- .../builders/UserInputQueryBuilder.java | 34 ++++++++++++++++--- .../apache/lucene/xmlparser/TestParser.java | 3 +- .../xmlparser/TestQueryTemplateManager.java | 3 +- 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java b/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java index b77439f2e6a..09904e620fb 100644 --- a/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java +++ b/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java @@ -59,7 +59,28 @@ public class CoreParser implements QueryBuilder public static int maxNumCachedFilters=20; + /** + * Construct an XML parser that uses a single instance QueryParser for handling + * UserQuery tags - all parse operations are synchronised on this parser + * @param analyzer + * @param parser A QueryParser which will be synchronized on during parse calls. + */ public CoreParser(Analyzer analyzer, QueryParser parser) + { + this(null,analyzer,parser); + } + + /** + * Constructs an XML parser that creates a QueryParser for each UserQuery request. + * @param defaultField The default field name used by QueryParsers constructed for UserQuery tags + * @param analyzer + */ + public CoreParser(String defaultField, Analyzer analyzer) + { + this(defaultField,analyzer,null); + } + + protected CoreParser(String defaultField,Analyzer analyzer, QueryParser parser) { this.analyzer=analyzer; this.parser=parser; @@ -72,7 +93,14 @@ public class CoreParser implements QueryBuilder queryFactory.addBuilder("TermsQuery",new TermsQueryBuilder(analyzer)); queryFactory.addBuilder("MatchAllDocsQuery",new MatchAllDocsQueryBuilder()); queryFactory.addBuilder("BooleanQuery",new BooleanQueryBuilder(queryFactory)); - queryFactory.addBuilder("UserQuery",new UserInputQueryBuilder(parser)); + if(parser!=null) + { + queryFactory.addBuilder("UserQuery",new UserInputQueryBuilder(parser)); + } + else + { + queryFactory.addBuilder("UserQuery",new UserInputQueryBuilder(defaultField,analyzer)); + } queryFactory.addBuilder("FilteredQuery",new FilteredQueryBuilder(filterFactory,queryFactory)); queryFactory.addBuilder("ConstantScoreQuery",new ConstantScoreQueryBuilder(filterFactory)); diff --git a/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CorePlusExtensionsParser.java b/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CorePlusExtensionsParser.java index 532cea8fa38..8b2036da383 100644 --- a/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CorePlusExtensionsParser.java +++ b/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CorePlusExtensionsParser.java @@ -27,9 +27,29 @@ import org.apache.lucene.xmlparser.builders.TermsFilterBuilder; public class CorePlusExtensionsParser extends CoreParser { + /** + * Construct an XML parser that uses a single instance QueryParser for handling + * UserQuery tags - all parse operations are synchronised on this parser + * @param analyzer + * @param parser A QueryParser which will be synchronized on during parse calls. + */ public CorePlusExtensionsParser(Analyzer analyzer, QueryParser parser) { - super(analyzer, parser); + this(null,analyzer, parser); + } + /** + * Constructs an XML parser that creates a QueryParser for each UserQuery request. + * @param defaultField The default field name used by QueryParsers constructed for UserQuery tags + * @param analyzer + */ + public CorePlusExtensionsParser(String defaultField,Analyzer analyzer) + { + this(defaultField,analyzer, null); + } + + private CorePlusExtensionsParser(String defaultField,Analyzer analyzer, QueryParser parser) + { + super(defaultField,analyzer, parser); filterFactory.addBuilder("TermsFilter",new TermsFilterBuilder(analyzer)); filterFactory.addBuilder("BooleanFilter",new BooleanFilterBuilder(filterFactory)); filterFactory.addBuilder("DuplicateFilter",new DuplicateFilterBuilder()); @@ -39,6 +59,4 @@ public class CorePlusExtensionsParser extends CoreParser queryFactory.addBuilder("FuzzyLikeThisQuery", new FuzzyLikeThisQueryBuilder(analyzer)); } - - } diff --git a/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/UserInputQueryBuilder.java b/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/UserInputQueryBuilder.java index 8c4046abea6..48fb23c68ef 100644 --- a/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/UserInputQueryBuilder.java +++ b/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/UserInputQueryBuilder.java @@ -1,5 +1,6 @@ package org.apache.lucene.xmlparser.builders; +import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Query; @@ -26,17 +27,28 @@ import org.w3c.dom.Element; */ /** + * UserInputQueryBuilder uses 1 of 2 strategies for thread-safe parsing: + * 1) Synchronizing access to "parse" calls on a previously supplied QueryParser + * or.. + * 2) creating a new QueryParser object for each parse request * @author maharwood */ public class UserInputQueryBuilder implements QueryBuilder { - QueryParser parser; + QueryParser unSafeParser; + private Analyzer analyzer; + private String defaultField; /** - * @param parser + * @param parser thread un-safe query parser */ public UserInputQueryBuilder(QueryParser parser) { - this.parser = parser; + this.unSafeParser = parser; + } + + public UserInputQueryBuilder(String defaultField, Analyzer analyzer) { + this.analyzer = analyzer; + this.defaultField = defaultField; } /* (non-Javadoc) @@ -45,7 +57,21 @@ public class UserInputQueryBuilder implements QueryBuilder { public Query getQuery(Element e) throws ParserException { String text=DOMUtils.getText(e); try { - Query q = parser.parse(text); + Query q = null; + if(unSafeParser!=null) + { + //synchronize on unsafe parser + synchronized (unSafeParser) + { + q = unSafeParser.parse(text); + } + } + else + { + //Create new parser + QueryParser parser=new QueryParser(defaultField,analyzer); + q = parser.parse(text); + } q.setBoost(DOMUtils.getAttribute(e,"boost",1.0f)); return q; } catch (ParseException e1) { diff --git a/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java b/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java index e55867fd360..4f483c97d05 100644 --- a/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java +++ b/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java @@ -12,7 +12,6 @@ import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; @@ -56,7 +55,7 @@ public class TestParser extends TestCase { super.setUp(); //initialize the parser - builder=new CorePlusExtensionsParser(analyzer,new QueryParser("contents", analyzer)); + builder=new CorePlusExtensionsParser("contents",analyzer); //initialize the index (done once, then cached in static data for use with ALL tests) if(dir==null) diff --git a/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestQueryTemplateManager.java b/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestQueryTemplateManager.java index 164e7cb7ef8..f52dcc31502 100644 --- a/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestQueryTemplateManager.java +++ b/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestQueryTemplateManager.java @@ -13,7 +13,6 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; @@ -154,7 +153,7 @@ public class TestQueryTemplateManager extends TestCase { searcher=new IndexSearcher(dir); //initialize the parser - builder=new CorePlusExtensionsParser(analyzer,new QueryParser("artist", analyzer)); + builder=new CorePlusExtensionsParser("artist", analyzer); }