// load up the elevation map private Map<String, ElevationObj> loadElevationMap(Config cfg) throws IOException { XPath xpath = XPathFactory.newInstance().newXPath(); Map<String, ElevationObj> map = new HashMap<String, ElevationObj>(); NodeList nodes = (NodeList) cfg.evaluate("elevate/query", XPathConstants.NODESET); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); String qstr = DOMUtil.getAttr(node, "text", "missing query 'text'"); NodeList children = null; try { children = (NodeList) xpath.evaluate("doc", node, XPathConstants.NODESET); } catch (XPathExpressionException e) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "query requires '<doc .../>' child"); } ArrayList<String> include = new ArrayList<String>(); ArrayList<String> exclude = new ArrayList<String>(); for (int j = 0; j < children.getLength(); j++) { Node child = children.item(j); String id = DOMUtil.getAttr(child, "id", "missing 'id'"); String e = DOMUtil.getAttr(child, EXCLUDE, null); if (e != null) { if (Boolean.valueOf(e)) { exclude.add(id); continue; } } include.add(id); } ElevationObj elev = new ElevationObj(qstr, include, exclude); if (map.containsKey(elev.analyzed)) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Boosting query defined twice for query: '" + elev.text + "' (" + elev.analyzed + "')"); } map.put(elev.analyzed, elev); } return map; }
// // <analyzer><tokenizer class="...."/><tokenizer class="...." arg="...."> // // private Analyzer readAnalyzer(final Node node) throws XPathExpressionException { // parent node used to be passed in as "fieldtype" // if (!fieldtype.hasChildNodes()) return null; // Node node = DOMUtil.getChild(fieldtype,"analyzer"); if (node == null) return null; final NamedNodeMap attrs = node.getAttributes(); final String analyzerName = DOMUtil.getAttr(attrs, "class"); if (analyzerName != null) { // No need to be core-aware as Analyzers are not in the core-aware list final Class<? extends Analyzer> clazz = loader.findClass(analyzerName).asSubclass(Analyzer.class); try { try { // first try to use a ctor with version parameter (needed for many new Analyzers that have // no default one anymore) final Constructor<? extends Analyzer> cnstr = clazz.getConstructor(Version.class); final String matchVersionStr = DOMUtil.getAttr(attrs, LUCENE_MATCH_VERSION_PARAM); final Version luceneMatchVersion = (matchVersionStr == null) ? this.luceneMatchVersion : Config.parseLuceneVersionString(matchVersionStr); if (luceneMatchVersion == null) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Configuration Error: Analyzer '" + clazz.getName() + "' needs a 'luceneMatchVersion' parameter"); } return cnstr.newInstance(luceneMatchVersion); } catch (final NoSuchMethodException nsme) { // otherwise use default ctor return clazz.newInstance(); } } catch (final Exception e) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Cannot load analyzer: " + analyzerName); } } final XPath xpath = XPathFactory.newInstance().newXPath(); // Load the CharFilters // -------------------------------------------------------------------------------- final ArrayList<CharFilterFactory> charFilters = new ArrayList<CharFilterFactory>(); final AbstractPluginLoader<CharFilterFactory> charFilterLoader = new AbstractPluginLoader<CharFilterFactory>( "[schema.xml] analyzer/charFilter", false, false) { @Override protected void init(final CharFilterFactory plugin, final Node node) throws Exception { if (plugin != null) { final Map<String, String> params = DOMUtil.toMapExcept(node.getAttributes(), "class"); // copy the luceneMatchVersion from config, if not set if (!params.containsKey(LUCENE_MATCH_VERSION_PARAM)) params.put(LUCENE_MATCH_VERSION_PARAM, luceneMatchVersion.toString()); plugin.init(params); charFilters.add(plugin); } } @Override protected CharFilterFactory register(final String name, final CharFilterFactory plugin) throws Exception { return null; // used for map registration } }; charFilterLoader.load( loader, (NodeList) xpath.evaluate("./charFilter", node, XPathConstants.NODESET)); // Load the Tokenizer // Although an analyzer only allows a single Tokenizer, we load a list to make sure // the configuration is ok // -------------------------------------------------------------------------------- final ArrayList<TokenizerFactory> tokenizers = new ArrayList<TokenizerFactory>(1); final AbstractPluginLoader<TokenizerFactory> tokenizerLoader = new AbstractPluginLoader<TokenizerFactory>( "[schema.xml] analyzer/tokenizer", false, false) { @Override protected void init(final TokenizerFactory plugin, final Node node) throws Exception { if (!tokenizers.isEmpty()) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "The schema defines multiple tokenizers for: " + node); } final Map<String, String> params = DOMUtil.toMapExcept(node.getAttributes(), "class"); // copy the luceneMatchVersion from config, if not set if (!params.containsKey(LUCENE_MATCH_VERSION_PARAM)) params.put(LUCENE_MATCH_VERSION_PARAM, luceneMatchVersion.toString()); plugin.init(params); tokenizers.add(plugin); } @Override protected TokenizerFactory register(final String name, final TokenizerFactory plugin) throws Exception { return null; // used for map registration } }; tokenizerLoader.load( loader, (NodeList) xpath.evaluate("./tokenizer", node, XPathConstants.NODESET)); // Make sure something was loaded if (tokenizers.isEmpty()) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "analyzer without class or tokenizer & filter list"); } // Load the Filters // -------------------------------------------------------------------------------- final ArrayList<TokenFilterFactory> filters = new ArrayList<TokenFilterFactory>(); final AbstractPluginLoader<TokenFilterFactory> filterLoader = new AbstractPluginLoader<TokenFilterFactory>("[schema.xml] analyzer/filter", false, false) { @Override protected void init(final TokenFilterFactory plugin, final Node node) throws Exception { if (plugin != null) { final Map<String, String> params = DOMUtil.toMapExcept(node.getAttributes(), "class"); // copy the luceneMatchVersion from config, if not set if (!params.containsKey(LUCENE_MATCH_VERSION_PARAM)) params.put(LUCENE_MATCH_VERSION_PARAM, luceneMatchVersion.toString()); plugin.init(params); filters.add(plugin); } } @Override protected TokenFilterFactory register(final String name, final TokenFilterFactory plugin) throws Exception { return null; // used for map registration } }; filterLoader.load(loader, (NodeList) xpath.evaluate("./filter", node, XPathConstants.NODESET)); return new TokenizerChain( charFilters.toArray(new CharFilterFactory[charFilters.size()]), tokenizers.get(0), filters.toArray(new TokenFilterFactory[filters.size()])); };
private void readSchema(final InputStream is) { log.info("Reading Solr Schema"); try { // pass the config resource loader to avoid building an empty one for no reason: // in the current case though, the stream is valid so we wont load the resource by name final Config schemaConf = new Config(loader, "schema", is, "/schema/"); final Document document = schemaConf.getDocument(); final XPath xpath = schemaConf.getXPath(); final List<SchemaAware> schemaAware = new ArrayList<SchemaAware>(); final Node nd = (Node) xpath.evaluate("/schema/@name", document, XPathConstants.NODE); if (nd == null) { log.warn("schema has no name!"); } else { name = nd.getNodeValue(); log.info("Schema name=" + name); } version = schemaConf.getFloat("/schema/@version", 1.0f); final AbstractPluginLoader<FieldType> fieldLoader = new AbstractPluginLoader<FieldType>("[schema.xml] fieldType", true, true) { @Override protected FieldType create( final ResourceLoader loader, final String name, final String className, final Node node) throws Exception { final FieldType ft = (FieldType) loader.newInstance(className); if (!(ft instanceof SubTextField)) { throw new SolrException(ErrorCode.FORBIDDEN, "Subschema must use SubTextField"); } ((SubTextField) ft).setTypeName(name); String expression = "./analyzer[@type='query']"; Node anode = (Node) xpath.evaluate(expression, node, XPathConstants.NODE); Analyzer queryAnalyzer = SubIndexSchema.this.readAnalyzer(anode); // An analyzer without a type specified, or with type="index" expression = "./analyzer[not(@type)] | ./analyzer[@type='index']"; anode = (Node) xpath.evaluate(expression, node, XPathConstants.NODE); Analyzer analyzer = SubIndexSchema.this.readAnalyzer(anode); if (queryAnalyzer == null) queryAnalyzer = analyzer; if (analyzer == null) analyzer = queryAnalyzer; if (analyzer != null) { ft.setAnalyzer(analyzer); ft.setQueryAnalyzer(queryAnalyzer); } return ft; } @Override protected void init(final FieldType plugin, final Node node) throws Exception {} @Override protected FieldType register(final String name, final FieldType plugin) throws Exception { log.trace("fieldtype defined: " + plugin); return fieldTypes.put(name, plugin); } }; final String expression = "/schema/types/fieldtype | /schema/types/fieldType"; final NodeList nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET); fieldLoader.load(loader, nodes); } catch (final SolrException e) { SolrConfig.severeErrors.add(e); throw e; } catch (final Exception e) { // unexpected exception... SolrConfig.severeErrors.add(e); throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Schema Parsing Failed", e, false); } }