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 @Override 10 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 @Override 10 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, software 11 # 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 and 14 # limitations under the License. 15 16 org.apache.lucene.codecs.lucene40.Lucene40Codec 17 org.apache.lucene.codecs.lucene3x.Lucene3xCodec 18 org.apache.lucene.codecs.lucene41.Lucene41Codec 19 org.apache.lucene.codecs.lucene42.Lucene42Codec 20 org.apache.lucene.codecs.lucene45.Lucene45Codec 21 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, all 121 * iterators ({@link #availableCodecs()},...) stay consistent. 122 * 123 * <p><b>NOTE:</b> Only new codecs are added, existing ones are 124 * never removed or replaced. 125 * 126 * <p><em>This method is expensive and should only be called for discovery 127 * 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.Lucene46Codec 135 * */ 136 private static Codec defaultCodec = Codec.forName("Lucene46"); 137 138 /** 139 * 返回默认的Codec实例 140 * */ 141 /** expert: returns the default codec used for newly created 142 * {@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 created 153 * {@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 provide 161 * more detail (such as parameters). 162 */ 163 @Override 164 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 @Override 128 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 @Override 131 public boolean hasNext() { 132 return linesIterator.hasNext() || loadNextProfile(); 133 } 134 135 @Override 136 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 @Override 153 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 @Override 102 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 @Override 125 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 @Override 135 public final NormsFormat normsFormat() { 136 return normsFormat; 137 } 138 }
来源:https://www.cnblogs.com/rcfeng/p/3932045.html