mirror of https://github.com/apache/lucene.git
Changes to improve server-side speed and thread safety by caching reusable, compiled stylesheets.
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@503500 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
842995a83c
commit
0149b5f82f
|
@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
@ -11,7 +12,9 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.transform.Result;
|
import javax.xml.transform.Result;
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
|
import javax.xml.transform.Templates;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerConfigurationException;
|
||||||
import javax.xml.transform.TransformerException;
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
import javax.xml.transform.dom.DOMResult;
|
import javax.xml.transform.dom.DOMResult;
|
||||||
|
@ -21,6 +24,7 @@ import javax.xml.transform.stream.StreamResult;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -43,6 +47,8 @@ import org.xml.sax.SAXException;
|
||||||
* and changing how user input is turned into Lucene queries.
|
* and changing how user input is turned into Lucene queries.
|
||||||
* Database applications often adopt similar practices by externalizing SQL in template files that can
|
* Database applications often adopt similar practices by externalizing SQL in template files that can
|
||||||
* be easily changed/optimized by a DBA.
|
* be easily changed/optimized by a DBA.
|
||||||
|
* The static methods can be used on their own or by creating an instance of this class you can store and
|
||||||
|
* re-use compiled stylesheets for fast use (e.g. in a server environment)
|
||||||
* @author Mark Harwood
|
* @author Mark Harwood
|
||||||
*/
|
*/
|
||||||
public class QueryTemplateManager
|
public class QueryTemplateManager
|
||||||
|
@ -50,42 +56,127 @@ public class QueryTemplateManager
|
||||||
static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
|
static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
|
||||||
static TransformerFactory tFactory = TransformerFactory.newInstance();
|
static TransformerFactory tFactory = TransformerFactory.newInstance();
|
||||||
|
|
||||||
public static String getQueryAsXmlString(Properties formProperties, String templateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
HashMap compiledTemplatesCache=new HashMap();
|
||||||
|
Templates defaultCompiledTemplates=null;
|
||||||
|
|
||||||
|
|
||||||
|
public QueryTemplateManager()
|
||||||
{
|
{
|
||||||
return getQueryAsXmlString(formProperties,
|
|
||||||
getDOMSource(QueryTemplateManager.class.getResourceAsStream(templateName)));
|
}
|
||||||
|
public QueryTemplateManager(InputStream xslIs) throws TransformerConfigurationException, ParserConfigurationException, SAXException, IOException
|
||||||
|
{
|
||||||
|
addDefaultQueryTemplate(xslIs);
|
||||||
|
}
|
||||||
|
public void addDefaultQueryTemplate(InputStream xslIs) throws TransformerConfigurationException, ParserConfigurationException, SAXException, IOException
|
||||||
|
{
|
||||||
|
defaultCompiledTemplates=getTemplates(xslIs);
|
||||||
|
}
|
||||||
|
public void addQueryTemplate(String name, InputStream xslIs) throws TransformerConfigurationException, ParserConfigurationException, SAXException, IOException
|
||||||
|
{
|
||||||
|
compiledTemplatesCache.put(name,getTemplates(xslIs));
|
||||||
|
}
|
||||||
|
public String getQueryAsXmlString(Properties formProperties,String queryTemplateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
|
{
|
||||||
|
Templates ts=(Templates) compiledTemplatesCache.get(queryTemplateName);
|
||||||
|
return getQueryAsXmlString(formProperties, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getQueryAsXmlString(Properties formProperties, Source xslDs) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
public Document getQueryAsDOM(Properties formProperties,String queryTemplateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
|
{
|
||||||
|
Templates ts=(Templates) compiledTemplatesCache.get(queryTemplateName);
|
||||||
|
return getQueryAsDOM(formProperties, ts);
|
||||||
|
}
|
||||||
|
public String getQueryAsXmlString(Properties formProperties) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
|
{
|
||||||
|
return getQueryAsXmlString(formProperties, defaultCompiledTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Document getQueryAsDOM(Properties formProperties) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
|
{
|
||||||
|
return getQueryAsDOM(formProperties, defaultCompiledTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast means of constructing query using a precompiled stylesheet
|
||||||
|
*/
|
||||||
|
public static String getQueryAsXmlString(Properties formProperties, Templates template) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
{
|
{
|
||||||
ByteArrayOutputStream baos=new ByteArrayOutputStream();
|
ByteArrayOutputStream baos=new ByteArrayOutputStream();
|
||||||
StreamResult result=new StreamResult(baos);
|
StreamResult result=new StreamResult(baos);
|
||||||
transformCriteria(formProperties,xslDs,result);
|
transformCriteria(formProperties,template,result);
|
||||||
return baos.toString();
|
return baos.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Document getQueryAsDOM(Properties formProperties, String templateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
/**
|
||||||
|
* Slow means of constructing query parsing a stylesheet from an input stream
|
||||||
|
*/
|
||||||
|
public static String getQueryAsXmlString(Properties formProperties, InputStream xslIs) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
{
|
{
|
||||||
return getQueryAsDOM(formProperties, getDOMSource(QueryTemplateManager.class.getResourceAsStream(templateName)));
|
ByteArrayOutputStream baos=new ByteArrayOutputStream();
|
||||||
}
|
StreamResult result=new StreamResult(baos);
|
||||||
public static Document getQueryAsDOM(Properties formProperties, InputStream xslIs) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
transformCriteria(formProperties,xslIs,result);
|
||||||
{
|
return baos.toString();
|
||||||
return getQueryAsDOM(formProperties, getDOMSource(xslIs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Document getQueryAsDOM(Properties formProperties, Source xslDs) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
/**
|
||||||
|
* Fast means of constructing query using a cached,precompiled stylesheet
|
||||||
|
*/
|
||||||
|
public static Document getQueryAsDOM(Properties formProperties, Templates template) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
{
|
{
|
||||||
DOMResult result=new DOMResult();
|
DOMResult result=new DOMResult();
|
||||||
transformCriteria(formProperties,xslDs,result);
|
transformCriteria(formProperties,template,result);
|
||||||
return (Document)result.getNode();
|
return (Document)result.getNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void transformCriteria(Properties formProperties, Source xslDs, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
|
||||||
|
/**
|
||||||
|
* Slow means of constructing query - parses stylesheet from input stream
|
||||||
|
*/
|
||||||
|
public static Document getQueryAsDOM(Properties formProperties, InputStream xslIs) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
|
{
|
||||||
|
DOMResult result=new DOMResult();
|
||||||
|
transformCriteria(formProperties,xslIs,result);
|
||||||
|
return (Document)result.getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slower transformation using an uncompiled stylesheet (suitable for development environment)
|
||||||
|
*/
|
||||||
|
public static void transformCriteria(Properties formProperties, InputStream xslIs, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
|
{
|
||||||
|
dbf.setNamespaceAware(true);
|
||||||
|
DocumentBuilder builder = dbf.newDocumentBuilder();
|
||||||
|
org.w3c.dom.Document xslDoc = builder.parse(xslIs);
|
||||||
|
DOMSource ds = new DOMSource(xslDoc);
|
||||||
|
|
||||||
|
Transformer transformer =null;
|
||||||
|
synchronized (tFactory)
|
||||||
|
{
|
||||||
|
transformer = tFactory.newTransformer(ds);
|
||||||
|
}
|
||||||
|
transformCriteria(formProperties,transformer,result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast transformation using a pre-compiled stylesheet (suitable for production environments)
|
||||||
|
*/
|
||||||
|
public static void transformCriteria(Properties formProperties, Templates template, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
|
{
|
||||||
|
transformCriteria(formProperties,template.newTransformer(),result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void transformCriteria(Properties formProperties, Transformer transformer, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
|
||||||
{
|
{
|
||||||
dbf.setNamespaceAware(true);
|
dbf.setNamespaceAware(true);
|
||||||
|
|
||||||
Transformer transformer = tFactory.newTransformer(xslDs);
|
|
||||||
//Create an XML document representing the search index document.
|
//Create an XML document representing the search index document.
|
||||||
DocumentBuilder db = dbf.newDocumentBuilder ();
|
DocumentBuilder db = dbf.newDocumentBuilder ();
|
||||||
org.w3c.dom.Document doc = db.newDocument ();
|
org.w3c.dom.Document doc = db.newDocument ();
|
||||||
|
@ -107,11 +198,15 @@ public class QueryTemplateManager
|
||||||
transformer.transform(xml,result);
|
transformer.transform(xml,result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DOMSource getDOMSource(InputStream xslIs) throws ParserConfigurationException, SAXException, IOException
|
/**
|
||||||
|
* Parses a query stylesheet for repeated use
|
||||||
|
*/
|
||||||
|
public static Templates getTemplates(InputStream xslIs) throws ParserConfigurationException, SAXException, IOException, TransformerConfigurationException
|
||||||
{
|
{
|
||||||
dbf.setNamespaceAware(true);
|
dbf.setNamespaceAware(true);
|
||||||
DocumentBuilder builder = dbf.newDocumentBuilder();
|
DocumentBuilder builder = dbf.newDocumentBuilder();
|
||||||
org.w3c.dom.Document xslDoc = builder.parse(xslIs);
|
org.w3c.dom.Document xslDoc = builder.parse(xslIs);
|
||||||
return new DOMSource(xslDoc);
|
DOMSource ds = new DOMSource(xslDoc);
|
||||||
|
return tFactory.newTemplates(ds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package org.apache.lucene.xmlparser;
|
package org.apache.lucene.xmlparser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.transform.Source;
|
|
||||||
import javax.xml.transform.TransformerException;
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
@ -24,6 +20,7 @@ import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.store.RAMDirectory;
|
import org.apache.lucene.store.RAMDirectory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -49,7 +46,6 @@ public class TestQueryTemplateManager extends TestCase {
|
||||||
|
|
||||||
CoreParser builder;
|
CoreParser builder;
|
||||||
Analyzer analyzer=new StandardAnalyzer();
|
Analyzer analyzer=new StandardAnalyzer();
|
||||||
HashMap templates=new HashMap();
|
|
||||||
private IndexSearcher searcher;
|
private IndexSearcher searcher;
|
||||||
|
|
||||||
//A collection of documents' field values for use in our tests
|
//A collection of documents' field values for use in our tests
|
||||||
|
@ -66,26 +62,31 @@ public class TestQueryTemplateManager extends TestCase {
|
||||||
// a choice of query style template to use in the test, with expected number of hits
|
// a choice of query style template to use in the test, with expected number of hits
|
||||||
String queryForms[]=
|
String queryForms[]=
|
||||||
{
|
{
|
||||||
"artist=Fugazi \texpectedMatches=2 \ttemplate=albumBooleanQuery.xsl",
|
"artist=Fugazi \texpectedMatches=2 \ttemplate=albumBooleanQuery",
|
||||||
"artist=Fugazi \treleaseDate=1990 \texpectedMatches=1 \ttemplate=albumBooleanQuery.xsl",
|
"artist=Fugazi \treleaseDate=1990 \texpectedMatches=1 \ttemplate=albumBooleanQuery",
|
||||||
"artist=Buckley \tgenre=rock \texpectedMatches=1 \ttemplate=albumFilteredQuery.xsl",
|
"artist=Buckley \tgenre=rock \texpectedMatches=1 \ttemplate=albumFilteredQuery",
|
||||||
"artist=Buckley \tgenre=electronic \texpectedMatches=0 \ttemplate=albumFilteredQuery.xsl",
|
"artist=Buckley \tgenre=electronic \texpectedMatches=0 \ttemplate=albumFilteredQuery",
|
||||||
"queryString=artist:buckly~ NOT genre:electronic \texpectedMatches=1 \ttemplate=albumLuceneClassicQuery.xsl"
|
"queryString=artist:buckly~ NOT genre:electronic \texpectedMatches=1 \ttemplate=albumLuceneClassicQuery"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public void testFormTransforms() throws SAXException, IOException, ParserConfigurationException, TransformerException, ParserException
|
public void testFormTransforms() throws SAXException, IOException, ParserConfigurationException, TransformerException, ParserException
|
||||||
{
|
{
|
||||||
|
//Cache all the query templates we will be referring to.
|
||||||
|
QueryTemplateManager qtm=new QueryTemplateManager();
|
||||||
|
qtm.addQueryTemplate("albumBooleanQuery", getClass().getResourceAsStream("albumBooleanQuery.xsl"));
|
||||||
|
qtm.addQueryTemplate("albumFilteredQuery", getClass().getResourceAsStream("albumFilteredQuery.xsl"));
|
||||||
|
qtm.addQueryTemplate("albumLuceneClassicQuery", getClass().getResourceAsStream("albumLuceneClassicQuery.xsl"));
|
||||||
//Run all of our test queries
|
//Run all of our test queries
|
||||||
for (int i = 0; i < queryForms.length; i++)
|
for (int i = 0; i < queryForms.length; i++)
|
||||||
{
|
{
|
||||||
Properties queryFormProperties=getPropsFromString(queryForms[i]);
|
Properties queryFormProperties=getPropsFromString(queryForms[i]);
|
||||||
|
|
||||||
//Get the required query XSL template for this test
|
//Get the required query XSL template for this test
|
||||||
Source template=getTemplate(queryFormProperties.getProperty("template"));
|
// Templates template=getTemplate(queryFormProperties.getProperty("template"));
|
||||||
|
|
||||||
//Transform the queryFormProperties into a Lucene XML query
|
//Transform the queryFormProperties into a Lucene XML query
|
||||||
Document doc=QueryTemplateManager.getQueryAsDOM(queryFormProperties,template);
|
Document doc=qtm.getQueryAsDOM(queryFormProperties,queryFormProperties.getProperty("template"));
|
||||||
|
|
||||||
//Parse the XML query using the XML parser
|
//Parse the XML query using the XML parser
|
||||||
Query q=builder.getQuery(doc.getDocumentElement());
|
Query q=builder.getQuery(doc.getDocumentElement());
|
||||||
|
@ -100,20 +101,6 @@ public class TestQueryTemplateManager extends TestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Source getTemplate(String templateName) throws ParserConfigurationException, SAXException, IOException
|
|
||||||
{
|
|
||||||
Source result=(Source) templates.get(templateName);
|
|
||||||
if(result==null)
|
|
||||||
{
|
|
||||||
//Not yet loaded - load the stylesheet
|
|
||||||
result=QueryTemplateManager.getDOMSource(getClass().getResourceAsStream(templateName));
|
|
||||||
templates.put(templateName,result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Helper method to construct Lucene query forms used in our test
|
//Helper method to construct Lucene query forms used in our test
|
||||||
Properties getPropsFromString(String nameValuePairs)
|
Properties getPropsFromString(String nameValuePairs)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue