首页 > 代码库 > 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