首页 > 代码库 > Solr4.8.0源码分析(7)之Solr SPI

Solr4.8.0源码分析(7)之Solr SPI

Solr4.8.0源码分析(7)之Solr SPI

查看Solr源码时候会发现,每一个package都会由对应的resources. 如下图所示:

一时对这玩意好奇了,看了文档以后才发现,这个services就是java SPI机制。首先介绍下java SPI机制,然后再结合Solr谈一下SPI。

1. JAVA SPI

当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 

基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。

jdk提供服务实现查找的一个工具类:java.util.ServiceLoader

假设有一个内容搜索系统,分为展示和搜索两个模块。展示和搜索基于接口编程。搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索。实例代码如下:

Search.java: 搜索接口

1 package search;2 3 import java.util.List;4 5 import definition.Doc;6 7 public interface Search {8     List<Doc> search(String keyword);9 }

FileSearch.java:文件系统的搜索实现

 1 package search; 2  3 import java.util.List; 4  5 import definition.Doc; 6  7 public class FileSearch implements Search { 8  9     @Override10     public List<Doc> search(String keyword) {11         System.out.println("now use file system search. keyword:" + keyword);12         return null;13     }14 15 }

DatabaseSearch.java

 1 package search; 2  3 import java.util.List; 4  5 import definition.Doc; 6  7 public class DatabaseSearch implements Search { 8  9     @Override10     public List<Doc> search(String keyword) {11         System.out.println("now use database search. keyword:" + keyword);12         return null;13     }14 15 }

SearchTest.java

 1 package search; 2  3 import java.util.Iterator; 4 import java.util.ServiceLoader; 5  6 public class SearchTest { 7  8     public static void main(String[] args) { 9         ServiceLoader<Search> s = ServiceLoader.load(Search.class);10         Iterator<Search> searchs = s.iterator();11         if (searchs.hasNext()) {12             Search curSearch = searchs.next();13             curSearch.search("test");14         }15     }16 }

最后创建在META-INF/searvices/search.Search文件。

当search.Search文件内容是"search.FileSearch"时,程序输出是:

now use file system search. keyword:test

当search.Search文件内容是"search.DatabaseSearch"时,程序输出是:

now use database search. keyword:test 
可以看出SearchTest里没有任何和具体实现有关的代码,而是基于spi的机制去查找服务的实现。

 

2. Solr SPI

以Codec类为例,查看resources/META-INF/services/org.apache.lucene.codecs.Codec:可以看出Codec服务接口具有以下具体的实现类。这就很好的解释了Solrconfig.xml里面的LuceneVersion的配置,也为Lucene的向前兼容提供了保障。

 1 #  Licensed to the Apache Software Foundation (ASF) under one or more 2 #  contributor license agreements.  See the NOTICE file distributed with 3 #  this work for additional information regarding copyright ownership. 4 #  The ASF licenses this file to You under the Apache License, Version 2.0 5 #  (the "License"); you may not use this file except in compliance with 6 #  the License.  You may obtain a copy of the License at 7 # 8 #       http://www.apache.org/licenses/LICENSE-2.0 9 #10 #  Unless required by applicable law or agreed to in writing, software11 #  distributed under the License is distributed on an "AS IS" BASIS,12 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 #  See the License for the specific language governing permissions and14 #  limitations under the License.15 16 org.apache.lucene.codecs.lucene40.Lucene40Codec17 org.apache.lucene.codecs.lucene3x.Lucene3xCodec18 org.apache.lucene.codecs.lucene41.Lucene41Codec19 org.apache.lucene.codecs.lucene42.Lucene42Codec20 org.apache.lucene.codecs.lucene45.Lucene45Codec21 org.apache.lucene.codecs.lucene46.Lucene46Codec

接下来可以看下Codec服务接口的实现代码

  1 package org.apache.lucene.codecs;  2   3 /*  4  * Licensed to the Apache Software Foundation (ASF) under one or more  5  * contributor license agreements.  See the NOTICE file distributed with  6  * this work for additional information regarding copyright ownership.  7  * The ASF licenses this file to You under the Apache License, Version 2.0  8  * (the "License"); you may not use this file except in compliance with  9  * the License.  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 import java.util.Set; 21 import java.util.ServiceLoader; // javadocs 22  23 import org.apache.lucene.index.IndexWriterConfig; // javadocs 24 import org.apache.lucene.util.NamedSPILoader; 25  26 /** 27  * Encodes/decodes an inverted index segment. 28  * <p> 29  * Note, when extending this class, the name ({@link #getName}) is  30  * written into the index. In order for the segment to be read, the 31  * name must resolve to your implementation via {@link #forName(String)}. 32  * This method uses Java‘s  33  * {@link ServiceLoader Service Provider Interface} (SPI) to resolve codec names. 34  * <p> 35  * If you implement your own codec, make sure that it has a no-arg constructor 36  * so SPI can load it. 37  * @see ServiceLoader 38  */ 39 public abstract class Codec implements NamedSPILoader.NamedSPI { 40    41   private static final NamedSPILoader<Codec> loader = 42     new NamedSPILoader<>(Codec.class); 43  44   private final String name; 45  46   /** 47    * Creates a new codec. 48    * <p> 49    * The provided name will be written into the index segment: in order to 50    * for the segment to be read this class should be registered with Java‘s 51    * SPI mechanism (registered in META-INF/ of your jar file, etc). 52    * @param name must be all ascii alphanumeric, and less than 128 characters in length. 53    */ 54   protected Codec(String name) { 55     NamedSPILoader.checkServiceName(name); 56     this.name = name; 57   } 58    59   /** Returns this codec‘s name */ 60   @Override 61   public final String getName() { 62     return name; 63   } 64   /** 65    * 以下几个Format跟Lucene的索引文件格式有关 66    * */ 67   /** Encodes/decodes postings */ 68   public abstract PostingsFormat postingsFormat(); 69  70   /** Encodes/decodes docvalues */ 71   public abstract DocValuesFormat docValuesFormat(); 72    73   /** Encodes/decodes stored fields */ 74   public abstract StoredFieldsFormat storedFieldsFormat(); 75    76   /** Encodes/decodes term vectors */ 77   public abstract TermVectorsFormat termVectorsFormat(); 78    79   /** Encodes/decodes field infos file */ 80   public abstract FieldInfosFormat fieldInfosFormat(); 81    82   /** Encodes/decodes segment info file */ 83   public abstract SegmentInfoFormat segmentInfoFormat(); 84    85   /** Encodes/decodes document normalization values */ 86   public abstract NormsFormat normsFormat(); 87  88   /** Encodes/decodes live docs */ 89   public abstract LiveDocsFormat liveDocsFormat(); 90    91   /** 92    * 根据名字在已有的Codec实例中寻找符合 93    * */ 94   /** looks up a codec by name */ 95   public static Codec forName(String name) { 96     if (loader == null) { 97       throw new IllegalStateException("You called Codec.forName() before all Codecs could be initialized. "+ 98           "This likely happens if you call it from a Codec‘s ctor."); 99     }100     return loader.lookup(name);101   }102   103   /**104    * 返回有效的Codecs实例105    * */106   /** returns a list of all available codec names */107   public static Set<String> availableCodecs() {108     if (loader == null) {109       throw new IllegalStateException("You called Codec.availableCodecs() before all Codecs could be initialized. "+110           "This likely happens if you call it from a Codec‘s ctor.");111     }112     return loader.availableServices();113   }114   115   /**116    * 更新Codec实例列表,Codec实例列表只能添加,不能删除与更改。117    * */118   /** 119    * Reloads the codec list from the given {@link ClassLoader}.120    * Changes to the codecs are visible after the method ends, all121    * iterators ({@link #availableCodecs()},...) stay consistent. 122    * 123    * <p><b>NOTE:</b> Only new codecs are added, existing ones are124    * never removed or replaced.125    * 126    * <p><em>This method is expensive and should only be called for discovery127    * of new codecs on the given classpath/classloader!</em>128    */129   public static void reloadCodecs(ClassLoader classloader) {130     loader.reload(classloader);131   }132   133   /**134    * 默认为Lucene46,也就是说默认调用的是org.apache.lucene.codecs.lucene46.Lucene46Codec135    * */136   private static Codec defaultCodec = Codec.forName("Lucene46");137   138   /**139    * 返回默认的Codec实例140    * */141   /** expert: returns the default codec used for newly created142    *  {@link IndexWriterConfig}s.143    */144   // TODO: should we use this, or maybe a system property is better?145   public static Codec getDefault() {146     return defaultCodec;147   }148   149   /**150    * 设置默认的Codec实例151    * */152   /** expert: sets the default codec used for newly created153    *  {@link IndexWriterConfig}s.154    */155   public static void setDefault(Codec codec) {156     defaultCodec = codec;157   }158 159   /**160    * returns the codec‘s name. Subclasses can override to provide161    * more detail (such as parameters).162    */163   @Override164   public String toString() {165     return name;166   }167 }

代码比较简单明了,接下来再看下NamedSPILoader.NamedSPI,它封装了JAVA SPI的实现:

  1 package org.apache.lucene.util;  2   3 /*  4  * Licensed to the Apache Software Foundation (ASF) under one or more  5  * contributor license agreements.  See the NOTICE file distributed with  6  * this work for additional information regarding copyright ownership.  7  * The ASF licenses this file to You under the Apache License, Version 2.0  8  * (the "License"); you may not use this file except in compliance with  9  * the License.  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 import java.util.Collections; 21 import java.util.Iterator; 22 import java.util.Map; 23 import java.util.LinkedHashMap; 24 import java.util.Set; 25 import java.util.ServiceConfigurationError; 26  27 /** 28  * Helper class for loading named SPIs from classpath (e.g. Codec, PostingsFormat). 29  * @lucene.internal 30  */ 31 public final class NamedSPILoader<S extends NamedSPILoader.NamedSPI> implements Iterable<S> { 32  33   /** 34    * SPI service Map,存放服务对应的实例类。 35    * */ 36   private volatile Map<String,S> services = Collections.emptyMap(); 37   private final Class<S> clazz; 38  39   public NamedSPILoader(Class<S> clazz) { 40     this(clazz, Thread.currentThread().getContextClassLoader()); 41   } 42    43   public NamedSPILoader(Class<S> clazz, ClassLoader classloader) { 44     this.clazz = clazz; 45     // if clazz‘ classloader is not a parent of the given one, we scan clazz‘s classloader, too: 46     final ClassLoader clazzClassloader = clazz.getClassLoader(); 47     if (clazzClassloader != null && !SPIClassIterator.isParentClassLoader(clazzClassloader, classloader)) { 48       reload(clazzClassloader); 49     } 50     reload(classloader); 51   } 52    53   /** 54    * 更新SPI MAP services。遍历META-INF/services文件,如果services MAP没有该实例,则新建实例,并放入services MAP 55    * */ 56   /**  57    * Reloads the internal SPI list from the given {@link ClassLoader}. 58    * Changes to the service list are visible after the method ends, all 59    * iterators ({@link #iterator()},...) stay consistent.  60    *  61    * <p><b>NOTE:</b> Only new service providers are added, existing ones are 62    * never removed or replaced. 63    *  64    * <p><em>This method is expensive and should only be called for discovery 65    * of new service providers on the given classpath/classloader!</em> 66    */ 67   public synchronized void reload(ClassLoader classloader) { 68     final LinkedHashMap<String,S> services = new LinkedHashMap<>(this.services); 69     final SPIClassIterator<S> loader = SPIClassIterator.get(clazz, classloader); 70     while (loader.hasNext()) { 71       final Class<? extends S> c = loader.next(); 72       try { 73         final S service = c.newInstance(); 74         final String name = service.getName(); 75         // only add the first one for each name, later services will be ignored 76         // this allows to place services before others in classpath to make  77         // them used instead of others 78         if (!services.containsKey(name)) { 79           checkServiceName(name); 80           services.put(name, service); 81         } 82       } catch (Exception e) { 83         throw new ServiceConfigurationError("Cannot instantiate SPI class: " + c.getName(), e); 84       } 85     } 86     this.services = Collections.unmodifiableMap(services); 87   } 88    89   /** 90    * Validates that a service name meets the requirements of {@link NamedSPI} 91    */ 92   public static void checkServiceName(String name) { 93     // based on harmony charset.java 94     if (name.length() >= 128) { 95       throw new IllegalArgumentException("Illegal service name: ‘" + name + "‘ is too long (must be < 128 chars)."); 96     } 97     for (int i = 0, len = name.length(); i < len; i++) { 98       char c = name.charAt(i); 99       if (!isLetterOrDigit(c)) {100         throw new IllegalArgumentException("Illegal service name: ‘" + name + "‘ must be simple ascii alphanumeric.");101       }102     }103   }104   105   /**106    * Checks whether a character is a letter or digit (ascii) which are defined in the spec.107    */108   private static boolean isLetterOrDigit(char c) {109     return (‘a‘ <= c && c <= ‘z‘) || (‘A‘ <= c && c <= ‘Z‘) || (‘0‘ <= c && c <= ‘9‘);110   }111   112   /**113    * 在Services MAP里面查找是否已有name的实例114    * */115   public S lookup(String name) {116     final S service = services.get(name);117     if (service != null) return service;118     throw new IllegalArgumentException("A SPI class of type "+clazz.getName()+" with name ‘"+name+"‘ does not exist. "+119      "You need to add the corresponding JAR file supporting this SPI to your classpath."+120      "The current classpath supports the following names: "+availableServices());121   }122 123   public Set<String> availableServices() {124     return services.keySet();125   }126   127   @Override128   public Iterator<S> iterator() {129     return services.values().iterator();130   }131   132   /**133    * Interface to support {@link NamedSPILoader#lookup(String)} by name.134    * <p>135    * Names must be all ascii alphanumeric, and less than 128 characters in length.136    */137   public static interface NamedSPI {138     String getName();139   }140   141 }

接下来看看Solr是怎么获取services的实例信息的

  1 package org.apache.lucene.util;  2   3 /*  4  * Licensed to the Apache Software Foundation (ASF) under one or more  5  * contributor license agreements.  See the NOTICE file distributed with  6  * this work for additional information regarding copyright ownership.  7  * The ASF licenses this file to You under the Apache License, Version 2.0  8  * (the "License"); you may not use this file except in compliance with  9  * the License.  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 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.BufferedReader; 23 import java.io.InputStreamReader; 24 import java.net.URL; 25 import java.nio.charset.StandardCharsets; 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.Enumeration; 29 import java.util.Iterator; 30 import java.util.Locale; 31 import java.util.NoSuchElementException; 32 import java.util.ServiceConfigurationError; 33  34 /** 35  * Helper class for loading SPI classes from classpath (META-INF files). 36  * This is a light impl of {@link java.util.ServiceLoader} but is guaranteed to 37  * be bug-free regarding classpath order and does not instantiate or initialize 38  * the classes found. 39  * 40  * @lucene.internal 41  */ 42 public final class SPIClassIterator<S> implements Iterator<Class<? extends S>> { 43   //service路径 44   private static final String META_INF_SERVICES = "META-INF/services/"; 45  46   private final Class<S> clazz; 47   private final ClassLoader loader; 48   private final Enumeration<URL> profilesEnum; 49   private Iterator<String> linesIterator; 50    51   public static <S> SPIClassIterator<S> get(Class<S> clazz) { 52     return new SPIClassIterator<>(clazz, Thread.currentThread().getContextClassLoader()); 53   } 54    55   public static <S> SPIClassIterator<S> get(Class<S> clazz, ClassLoader loader) { 56     return new SPIClassIterator<>(clazz, loader); 57   } 58    59   /** Utility method to check if some class loader is a (grand-)parent of or the same as another one. 60    * This means the child will be able to load all classes from the parent, too. */ 61   public static boolean isParentClassLoader(final ClassLoader parent, ClassLoader child) { 62     while (child != null) { 63       if (child == parent) { 64         return true; 65       } 66       child = child.getParent(); 67     } 68     return false; 69   } 70    71   /** 72    * 解析META-INF/services/clazz.getname文件 73    * */ 74   private SPIClassIterator(Class<S> clazz, ClassLoader loader) { 75     this.clazz = clazz; 76     try { 77       final String fullName = META_INF_SERVICES + clazz.getName(); 78       this.profilesEnum = (loader == null) ? ClassLoader.getSystemResources(fullName) : loader.getResources(fullName); 79     } catch (IOException ioe) { 80       throw new ServiceConfigurationError("Error loading SPI profiles for type " + clazz.getName() + " from classpath", ioe); 81     } 82     this.loader = (loader == null) ? ClassLoader.getSystemClassLoader() : loader; 83     this.linesIterator = Collections.<String>emptySet().iterator(); 84   } 85    86   /** 87    * 获取META-INF/services/clazz.getname的clazz服务实例 88    * */ 89   private boolean loadNextProfile() { 90     ArrayList<String> lines = null; 91     while (profilesEnum.hasMoreElements()) { 92       if (lines != null) { 93         lines.clear(); 94       } else { 95         lines = new ArrayList<>(); 96       } 97       final URL url = profilesEnum.nextElement(); 98       try { 99         final InputStream in = url.openStream();100         IOException priorE = null;101         try {102           final BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));103           String line;104           while ((line = reader.readLine()) != null) {105             final int pos = line.indexOf(‘#‘);106             if (pos >= 0) {107               line = line.substring(0, pos);108             }109             line = line.trim();110             if (line.length() > 0) {111               lines.add(line);112             }113           }114         } catch (IOException ioe) {115           priorE = ioe;116         } finally {117           IOUtils.closeWhileHandlingException(priorE, in);118         }119       } catch (IOException ioe) {120         throw new ServiceConfigurationError("Error loading SPI class list from URL: " + url, ioe);121       }122       if (!lines.isEmpty()) {123         this.linesIterator = lines.iterator();124         return true;125       }126     }127     return false;128   }129   130   @Override131   public boolean hasNext() {132     return linesIterator.hasNext() || loadNextProfile();133   }134   135   @Override136   public Class<? extends S> next() {137     // hasNext() implicitely loads the next profile, so it is essential to call this here!138     if (!hasNext()) {139       throw new NoSuchElementException();140     }141     assert linesIterator.hasNext();142     final String c = linesIterator.next();143     try {144       // don‘t initialize the class (pass false as 2nd parameter):145       return Class.forName(c, false, loader).asSubclass(clazz);146     } catch (ClassNotFoundException cnfe) {147       throw new ServiceConfigurationError(String.format(Locale.ROOT, "A SPI class of type %s with classname %s does not exist, "+148         "please fix the file ‘%s%1$s‘ in your classpath.", clazz.getName(), c, META_INF_SERVICES));149     }150   }151   152   @Override153   public void remove() {154     throw new UnsupportedOperationException();155   }156   157 }

由此可见SOLR SPI的流程是如下的:以Codec为例

1.SPIClassIterator获取所有META-INF/services/org.apache.lucene.codecs.Codec的实例类信息

2.NamedSPILoader实例化所有META-INF/services/org.apache.lucene.codecs.Codec的实例类,并放入services MAP里面

3.Codec默认为Lucene46,从services MAP获取Lucene46的实例类org.apache.lucene.codecs.lucene46.Lucene46Codec

  1 package org.apache.lucene.codecs.lucene46;  2   3 /*  4  * Licensed to the Apache Software Foundation (ASF) under one or more  5  * contributor license agreements.  See the NOTICE file distributed with  6  * this work for additional information regarding copyright ownership.  7  * The ASF licenses this file to You under the Apache License, Version 2.0  8  * (the "License"); you may not use this file except in compliance with  9  * the License.  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 import org.apache.lucene.codecs.Codec; 21 import org.apache.lucene.codecs.DocValuesFormat; 22 import org.apache.lucene.codecs.FieldInfosFormat; 23 import org.apache.lucene.codecs.FilterCodec; 24 import org.apache.lucene.codecs.LiveDocsFormat; 25 import org.apache.lucene.codecs.NormsFormat; 26 import org.apache.lucene.codecs.PostingsFormat; 27 import org.apache.lucene.codecs.SegmentInfoFormat; 28 import org.apache.lucene.codecs.StoredFieldsFormat; 29 import org.apache.lucene.codecs.TermVectorsFormat; 30 import org.apache.lucene.codecs.lucene40.Lucene40LiveDocsFormat; 31 import org.apache.lucene.codecs.lucene41.Lucene41StoredFieldsFormat; 32 import org.apache.lucene.codecs.lucene42.Lucene42NormsFormat; 33 import org.apache.lucene.codecs.lucene42.Lucene42TermVectorsFormat; 34 import org.apache.lucene.codecs.perfield.PerFieldDocValuesFormat; 35 import org.apache.lucene.codecs.perfield.PerFieldPostingsFormat; 36  37 /** 38  * Implements the Lucene 4.6 index format, with configurable per-field postings 39  * and docvalues formats. 40  * <p> 41  * If you want to reuse functionality of this codec in another codec, extend 42  * {@link FilterCodec}. 43  * 44  * @see org.apache.lucene.codecs.lucene46 package documentation for file format details. 45  * @lucene.experimental 46  */ 47 // NOTE: if we make largish changes in a minor release, easier to just make Lucene46Codec or whatever 48 // if they are backwards compatible or smallish we can probably do the backwards in the postingsreader 49 // (it writes a minor version, etc). 50 public class Lucene46Codec extends Codec { 51   private final StoredFieldsFormat fieldsFormat = new Lucene41StoredFieldsFormat(); 52   private final TermVectorsFormat vectorsFormat = new Lucene42TermVectorsFormat(); 53   private final FieldInfosFormat fieldInfosFormat = new Lucene46FieldInfosFormat(); 54   private final SegmentInfoFormat segmentInfosFormat = new Lucene46SegmentInfoFormat(); 55   private final LiveDocsFormat liveDocsFormat = new Lucene40LiveDocsFormat(); 56    57   private final PostingsFormat postingsFormat = new PerFieldPostingsFormat() { 58     @Override 59     public PostingsFormat getPostingsFormatForField(String field) { 60       return Lucene46Codec.this.getPostingsFormatForField(field); 61     } 62   }; 63    64   private final DocValuesFormat docValuesFormat = new PerFieldDocValuesFormat() { 65     @Override 66     public DocValuesFormat getDocValuesFormatForField(String field) { 67       return Lucene46Codec.this.getDocValuesFormatForField(field); 68     } 69   }; 70  71   /** Sole constructor. */ 72   public Lucene46Codec() { 73     super("Lucene46"); 74   } 75    76   @Override 77   public final StoredFieldsFormat storedFieldsFormat() { 78     return fieldsFormat; 79   } 80    81   @Override 82   public final TermVectorsFormat termVectorsFormat() { 83     return vectorsFormat; 84   } 85  86   @Override 87   public final PostingsFormat postingsFormat() { 88     return postingsFormat; 89   } 90    91   @Override 92   public final FieldInfosFormat fieldInfosFormat() { 93     return fieldInfosFormat; 94   } 95    96   @Override 97   public final SegmentInfoFormat segmentInfoFormat() { 98     return segmentInfosFormat; 99   }100   101   @Override102   public final LiveDocsFormat liveDocsFormat() {103     return liveDocsFormat;104   }105 106   /** Returns the postings format that should be used for writing 107    *  new segments of <code>field</code>.108    *  109    *  The default implementation always returns "Lucene41"110    */111   public PostingsFormat getPostingsFormatForField(String field) {112     return defaultFormat;113   }114   115   /** Returns the docvalues format that should be used for writing 116    *  new segments of <code>field</code>.117    *  118    *  The default implementation always returns "Lucene45"119    */120   public DocValuesFormat getDocValuesFormatForField(String field) {121     return defaultDVFormat;122   }123   124   @Override125   public final DocValuesFormat docValuesFormat() {126     return docValuesFormat;127   }128 129   private final PostingsFormat defaultFormat = PostingsFormat.forName("Lucene41");130   private final DocValuesFormat defaultDVFormat = DocValuesFormat.forName("Lucene45");131 132   private final NormsFormat normsFormat = new Lucene42NormsFormat();133 134   @Override135   public final NormsFormat normsFormat() {136     return normsFormat;137   }138 }

 

Solr4.8.0源码分析(7)之Solr SPI