The private void registerDynamicCopyField can use the code which I gave . It is cleaner to use System.arrayCopy() rather than doing a manual copy
2008/7/19 <[EMAIL PROTECTED]>: > Author: ryan > Date: Fri Jul 18 14:43:42 2008 > New Revision: 678050 > > URL: http://svn.apache.org/viewvc?rev=678050&view=rev > Log: > SOLR-619 -- refactored IndexSchema so it allows registering copy fields > within SolrCoreAware.inform() > > Modified: > lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java > lucene/solr/trunk/src/test/org/apache/solr/schema/IndexSchemaTest.java > > Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java > URL: > http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java?rev=678050&r1=678049&r2=678050&view=diff > ============================================================================== > --- lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java > (original) > +++ lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java Fri > Jul 18 14:43:42 2008 > @@ -152,15 +152,29 @@ > * <p> > * Modifying this Map (or any item in it) will affect the real schema > * </p> > + * > + * <p> > + * NOTE: this function is not thread safe. However, it is safe to use > within the standard > + * <code>inform( SolrCore core )</code> function for > <code>SolrCoreAware</code> classes. > + * Outside <code>inform</code>, this could potentially throw a > ConcurrentModificationException > + * </p> > */ > public Map<String,SchemaField> getFields() { return fields; } > > /** > * Provides direct access to the Map containing all Field Types > - * in the index, keyed on fild type name. > + * in the index, keyed on field type name. > * > * <p> > - * Modifying this Map (or any item in it) will affect the real schema > + * Modifying this Map (or any item in it) will affect the real schema. > However if you > + * make any modifications, be sure to call [EMAIL PROTECTED] > IndexSchema#refreshAnalyzers()} to > + * update the Analyzers for the registered fields. > + * </p> > + * > + * <p> > + * NOTE: this function is not thread safe. However, it is safe to use > within the standard > + * <code>inform( SolrCore core )</code> function for > <code>SolrCoreAware</code> classes. > + * Outside <code>inform</code>, this could potentially throw a > ConcurrentModificationException > * </p> > */ > public Map<String,FieldType> getFieldTypes() { return fieldTypes; } > @@ -287,8 +301,19 @@ > } > return f; > } > - > - > + > + /** > + * This will re-create the Analyzers. If you make any modifications to > + * the Field map ([EMAIL PROTECTED] IndexSchema#getFields()}, this > function is required > + * to synch the internally cached field analyzers. > + * > + * @since solr 1.3 > + */ > + public void refreshAnalyzers() > + { > + analyzer = new SolrIndexAnalyzer(); > + queryAnalyzer = new SolrQueryAnalyzer(); > + } > > private class SolrIndexAnalyzer extends Analyzer { > protected final HashMap<String,Analyzer> analyzers; > @@ -567,9 +592,8 @@ > /////////////// parse out copyField commands /////////////// > // Map<String,ArrayList<SchemaField>> cfields = new > HashMap<String,ArrayList<SchemaField>>(); > // expression = "/schema/copyField"; > - > - ArrayList<DynamicCopy> dCopies = new ArrayList<DynamicCopy>(); > - > + > + dynamicCopyFields = new DynamicCopy[] {}; > expression = "//copyField"; > nodes = (NodeList) xpath.evaluate(expression, document, > XPathConstants.NODESET); > > @@ -580,48 +604,7 @@ > String source = DOMUtil.getAttr(attrs,"source","copyField > definition"); > String dest = DOMUtil.getAttr(attrs,"dest", "copyField > definition"); > > - boolean sourceIsPattern = isWildCard(source); > - boolean destIsPattern = isWildCard(dest); > - > - log.fine("copyField source='"+source+"' dest='"+dest+"'"); > - SchemaField d = getField(dest); > - > - if(sourceIsPattern) { > - if( destIsPattern ) { > - DynamicField df = null; > - for( DynamicField dd : dynamicFields ) { > - if( dd.regex.equals( dest ) ) { > - df = dd; > - break; > - } > - } > - if( df == null ) { > - throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, > "copyField dynamic destination must match a dynamicField." ); > - } > - dCopies.add(new DynamicDestCopy(source, df )); > - } > - else { > - dCopies.add(new DynamicCopy(source, d)); > - } > - } > - else if( destIsPattern ) { > - String msg = "copyField only supports a dynamic destination if > the source is also dynamic" ; > - throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg > ); > - } > - else { > - // retrieve the field to force an exception if it doesn't exist > - SchemaField f = getField(source); > - > - SchemaField[] destArr = copyFields.get(source); > - if (destArr==null) { > - destArr=new SchemaField[]{d}; > - } else { > - destArr = (SchemaField[])append(destArr,d); > - } > - copyFields.put(source,destArr); > - > - copyFieldTargetCounts.put(d, (copyFieldTargetCounts.containsKey(d) > ? copyFieldTargetCounts.get(d) + 1 : 1)); > - } > + registerCopyField(source, dest); > } > > for (Map.Entry<SchemaField, Integer> entry : > copyFieldTargetCounts.entrySet()) { > @@ -632,11 +615,6 @@ > } > } > > - log.finest("Dynamic Copied Fields:" + dCopies); > - > - // stuff it in a normal array for faster access > - dynamicCopyFields = (DynamicCopy[])dCopies.toArray(new > DynamicCopy[dCopies.size()]); > - > } catch (SolrException e) { > SolrConfig.severeErrors.add( e ); > throw e; > @@ -646,13 +624,86 @@ > throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,"Schema > Parsing Failed",e,false); > } > > - analyzer = new SolrIndexAnalyzer(); > - queryAnalyzer = new SolrQueryAnalyzer(); > + // create the field analyzers > + refreshAnalyzers(); > + } > + > + /** > + * <p> > + * NOTE: this function is not thread safe. However, it is safe to use > within the standard > + * <code>inform( SolrCore core )</code> function for > <code>SolrCoreAware</code> classes. > + * Outside <code>inform</code>, this could potentially throw a > ConcurrentModificationException > + * </p> > + * > + * @see SolrCoreAware > + */ > + public void registerCopyField( String source, String dest ) > + { > + boolean sourceIsPattern = isWildCard(source); > + boolean destIsPattern = isWildCard(dest); > + > + log.fine("copyField source='"+source+"' dest='"+dest+"'"); > + SchemaField d = getField(dest); > + > + if(sourceIsPattern) { > + if( destIsPattern ) { > + DynamicField df = null; > + for( DynamicField dd : dynamicFields ) { > + if( dd.regex.equals( dest ) ) { > + df = dd; > + break; > + } > + } > + if( df == null ) { > + throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, > "copyField dynamic destination must match a dynamicField." ); > + } > + registerDynamicCopyField(new DynamicDestCopy(source, df )); > + } > + else { > + registerDynamicCopyField(new DynamicCopy(source, d)); > + } > + } > + else if( destIsPattern ) { > + String msg = "copyField only supports a dynamic destination if the > source is also dynamic" ; > + throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg ); > + } > + else { > + // retrieve the field to force an exception if it doesn't exist > + SchemaField f = getField(source); > + > + SchemaField[] destArr = copyFields.get(source); > + if (destArr==null) { > + destArr=new SchemaField[]{d}; > + } else { > + destArr = (SchemaField[])append(destArr,d); > + } > + copyFields.put(source,destArr); > + > + copyFieldTargetCounts.put(d, (copyFieldTargetCounts.containsKey(d) ? > copyFieldTargetCounts.get(d) + 1 : 1)); > + } > + } > + > + private void registerDynamicCopyField( DynamicCopy dcopy ) > + { > + if( dynamicCopyFields == null ) { > + dynamicCopyFields = new DynamicCopy[] {dcopy}; > + } > + else { > + int i=0; > + DynamicCopy[] old = dynamicCopyFields; > + dynamicCopyFields = new DynamicCopy[dynamicCopyFields.length+1]; > + for( DynamicCopy dc : old ) { > + dynamicCopyFields[i++] = dc; > + } > + dynamicCopyFields[i++] = dcopy; > + old = null; > + } > + log.finest("Dynamic Copy Field:" + dcopy ); > } > > private static Object[] append(Object[] orig, Object item) { > Object[] newArr = > (Object[])java.lang.reflect.Array.newInstance(orig.getClass().getComponentType(), > orig.length+1); > - System.arraycopy(orig, 0, newArr, 0, orig.length); > + System.arraycopy(orig, 0, newArr, 0, orig.length); > newArr[orig.length] = item; > return newArr; > } > @@ -864,18 +915,18 @@ > > private DynamicField[] dynamicFields; > public SchemaField[] getDynamicFieldPrototypes() { > - SchemaField[] df = new SchemaField[dynamicFields.length]; > - for (int i=0;i<dynamicFields.length;i++) { > - df[i] = dynamicFields[i].prototype; > - } > - return df; > + SchemaField[] df = new SchemaField[dynamicFields.length]; > + for (int i=0;i<dynamicFields.length;i++) { > + df[i] = dynamicFields[i].prototype; > + } > + return df; > } > > public String getDynamicPattern(String fieldName) { > - for (DynamicField df : dynamicFields) { > - if (df.matches(fieldName)) return df.regex; > - } > - return null; > + for (DynamicField df : dynamicFields) { > + if (df.matches(fieldName)) return df.regex; > + } > + return null; > } > > /** > @@ -1024,19 +1075,19 @@ > */ > > public SchemaField[] getCopySources(String destField) { > - SchemaField f = getField(destField); > - if (!isCopyFieldTarget(f)) { > - return new SchemaField[0]; > - } > - List<SchemaField> sf = new ArrayList<SchemaField>(); > - for (Map.Entry<String, SchemaField[]> cfs : copyFields.entrySet()) { > - for (SchemaField cf : cfs.getValue()) { > - if (cf.getName().equals(destField)) { > - sf.add(getField(cfs.getKey())); > - } > - } > - } > - return sf.toArray(new SchemaField[1]); > + SchemaField f = getField(destField); > + if (!isCopyFieldTarget(f)) { > + return new SchemaField[0]; > + } > + List<SchemaField> sf = new ArrayList<SchemaField>(); > + for (Map.Entry<String, SchemaField[]> cfs : copyFields.entrySet()) { > + for (SchemaField cf : cfs.getValue()) { > + if (cf.getName().equals(destField)) { > + sf.add(getField(cfs.getKey())); > + } > + } > + } > + return sf.toArray(new SchemaField[1]); > } > /** > * Get all copy fields, both the static and the dynamic ones. > @@ -1091,10 +1142,3 @@ > } > > } > - > - > - > - > - > - > - > > Modified: > lucene/solr/trunk/src/test/org/apache/solr/schema/IndexSchemaTest.java > URL: > http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/schema/IndexSchemaTest.java?rev=678050&r1=678049&r2=678050&view=diff > ============================================================================== > --- lucene/solr/trunk/src/test/org/apache/solr/schema/IndexSchemaTest.java > (original) > +++ lucene/solr/trunk/src/test/org/apache/solr/schema/IndexSchemaTest.java > Fri Jul 18 14:43:42 2008 > @@ -20,8 +20,10 @@ > import java.util.HashMap; > import java.util.Map; > > +import org.apache.solr.client.solrj.SolrQuery; > import org.apache.solr.common.params.CommonParams; > import org.apache.solr.common.params.MapSolrParams; > +import org.apache.solr.common.params.ModifiableSolrParams; > import org.apache.solr.core.SolrCore; > import org.apache.solr.request.LocalSolrQueryRequest; > import org.apache.solr.request.SolrQueryRequest; > @@ -90,4 +92,41 @@ > assertTrue("wrong class", similarity instanceof > MockConfigurableSimilarity); > assertEquals("is there an echo?", > ((MockConfigurableSimilarity)similarity).getPassthrough()); > } > + > + public void testRuntimeFieldCreation() > + { > + // any field manipulation needs to happen when you know the core will not > + // be accepting any requests. Typically this is done within the inform() > + // method. Since this is a single threaded test, we can change the > fields > + // willi-nilly > + > + SolrCore core = h.getCore(); > + IndexSchema schema = core.getSchema(); > + final String fieldName = "runtimefield"; > + SchemaField sf = new SchemaField( fieldName, schema.getFieldTypes().get( > "string" ) ); > + schema.getFields().put( fieldName, sf ); > + > + // also register a new copy field (from our new field) > + schema.registerCopyField( fieldName, "dynamic_runtime" ); > + schema.refreshAnalyzers(); > + > + assertU(adoc("id", "10", "title", "test", fieldName, "aaa")); > + assertU(commit()); > + > + SolrQuery query = new SolrQuery( fieldName+":aaa" ); > + query.set( "indent", "true" ); > + SolrQueryRequest req = new LocalSolrQueryRequest( core, query ); > + > + assertQ("Make sure they got in", req > + ,"//[EMAIL PROTECTED]'1']" > + ,"//result/doc[1]/[EMAIL PROTECTED]'id'][.='10']" > + ); > + > + // Check to see if our copy field made it out safely > + query.setQuery( "dynamic_runtime:aaa" ); > + assertQ("Make sure they got in", req > + ,"//[EMAIL PROTECTED]'1']" > + ,"//result/doc[1]/[EMAIL PROTECTED]'id'][.='10']" > + ); > + } > } > > > -- --Noble Paul