77
88package org .elasticsearch .xpack .lucene .bwc .codecs ;
99
10- import org .apache .lucene .backward_codecs .lucene70 .Lucene70Codec ;
1110import org .apache .lucene .codecs .Codec ;
1211import org .apache .lucene .codecs .FieldInfosFormat ;
1312import org .apache .lucene .codecs .FieldsConsumer ;
1817import org .apache .lucene .codecs .PostingsFormat ;
1918import org .apache .lucene .codecs .SegmentInfoFormat ;
2019import org .apache .lucene .codecs .TermVectorsFormat ;
20+ import org .apache .lucene .codecs .perfield .PerFieldPostingsFormat ;
2121import org .apache .lucene .index .FieldInfo ;
2222import org .apache .lucene .index .FieldInfos ;
2323import org .apache .lucene .index .Fields ;
2727import org .apache .lucene .index .Terms ;
2828import org .apache .lucene .store .Directory ;
2929import org .apache .lucene .store .IOContext ;
30+ import org .apache .lucene .util .Version ;
3031import org .elasticsearch .xpack .lucene .bwc .codecs .lucene70 .BWCLucene70Codec ;
32+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene80 .BWCLucene80Codec ;
33+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene84 .BWCLucene84Codec ;
34+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene86 .BWCLucene86Codec ;
35+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene87 .BWCLucene87Codec ;
3136
3237import java .io .IOException ;
3338import java .util .ArrayList ;
3944 */
4045public abstract class BWCCodec extends Codec {
4146
47+ private final FieldInfosFormat fieldInfosFormat ;
48+ private final SegmentInfoFormat segmentInfosFormat ;
49+ private final PostingsFormat postingsFormat ;
50+
4251 protected BWCCodec (String name ) {
4352 super (name );
44- }
4553
46- @ Override
47- public NormsFormat normsFormat () {
48- throw new UnsupportedOperationException ();
49- }
54+ this .fieldInfosFormat = new FieldInfosFormat () {
55+ final FieldInfosFormat wrappedFormat = originalFieldInfosFormat ();
5056
51- @ Override
52- public TermVectorsFormat termVectorsFormat () {
53- throw new UnsupportedOperationException ();
54- }
57+ @ Override
58+ public FieldInfos read (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , IOContext iocontext )
59+ throws IOException {
60+ return filterFields (wrappedFormat .read (directory , segmentInfo , segmentSuffix , iocontext ));
61+ }
5562
56- @ Override
57- public KnnVectorsFormat knnVectorsFormat () {
58- throw new UnsupportedOperationException ();
59- }
63+ @ Override
64+ public void write (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , FieldInfos infos , IOContext context )
65+ throws IOException {
66+ wrappedFormat .write (directory , segmentInfo , segmentSuffix , infos , context );
67+ }
68+ };
69+
70+ this .segmentInfosFormat = new SegmentInfoFormat () {
71+ final SegmentInfoFormat wrappedFormat = originalSegmentInfoFormat ();
6072
61- protected static SegmentInfoFormat wrap (SegmentInfoFormat wrapped ) {
62- return new SegmentInfoFormat () {
6373 @ Override
6474 public SegmentInfo read (Directory directory , String segmentName , byte [] segmentID , IOContext context ) throws IOException {
65- return wrap (wrapped .read (directory , segmentName , segmentID , context ));
75+ return wrap (wrappedFormat .read (directory , segmentName , segmentID , context ));
6676 }
6777
6878 @ Override
6979 public void write (Directory dir , SegmentInfo info , IOContext ioContext ) throws IOException {
70- wrapped .write (dir , info , ioContext );
80+ wrappedFormat .write (dir , info , ioContext );
7181 }
7282 };
73- }
7483
75- protected static FieldInfosFormat wrap (FieldInfosFormat wrapped ) {
76- return new FieldInfosFormat () {
84+ this .postingsFormat = new PerFieldPostingsFormat () {
7785 @ Override
78- public FieldInfos read (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , IOContext iocontext )
79- throws IOException {
80- return filterFields (wrapped .read (directory , segmentInfo , segmentSuffix , iocontext ));
81- }
82-
83- @ Override
84- public void write (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , FieldInfos infos , IOContext context )
85- throws IOException {
86- wrapped .write (directory , segmentInfo , segmentSuffix , infos , context );
86+ public PostingsFormat getPostingsFormatForField (String field ) {
87+ throw new UnsupportedOperationException ("Old codecs can't be used for writing" );
8788 }
8889 };
8990 }
9091
92+ @ Override
93+ public final FieldInfosFormat fieldInfosFormat () {
94+ return fieldInfosFormat ;
95+ }
96+
97+ @ Override
98+ public final SegmentInfoFormat segmentInfoFormat () {
99+ return segmentInfosFormat ;
100+ }
101+
102+ @ Override
103+ public PostingsFormat postingsFormat () {
104+ return postingsFormat ;
105+ }
106+
107+ /**
108+ * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}.
109+ * This method is never called in practice, as we rewrite field infos to override the info about which features are present in
110+ * the index. Even if norms are present, field info lies about it.
111+ *
112+ * @return nothing, as this method always throws an exception
113+ * @throws UnsupportedOperationException always thrown to indicate that this method is not supported
114+ */
115+ @ Override
116+ public final NormsFormat normsFormat () {
117+ throw new UnsupportedOperationException ();
118+ }
119+
120+ /**
121+ * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}.
122+ * This method is never called in practice, as we rewrite field infos to override the info about which features are present in
123+ * the index. Even if term vectors are present, field info lies about it.
124+ *
125+ * @return nothing, as this method always throws an exception
126+ * @throws UnsupportedOperationException always thrown to indicate that this method is not supported
127+ */
128+ @ Override
129+ public final TermVectorsFormat termVectorsFormat () {
130+ throw new UnsupportedOperationException ();
131+ }
132+
133+ /**
134+ * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}.
135+ * The knn vectors can't be present because it is not supported yet in any of the lucene versions that we support for archive indices.
136+ *
137+ * @return nothing, as this method always throws an exception
138+ * @throws UnsupportedOperationException always thrown to indicate that this method is not supported
139+ */
140+ @ Override
141+ public final KnnVectorsFormat knnVectorsFormat () {
142+ throw new UnsupportedOperationException ();
143+ }
144+
145+ /**
146+ * Returns the original {@link SegmentInfoFormat} used by this codec.
147+ * This method should be implemented by subclasses to provide the specific
148+ * {@link SegmentInfoFormat} that this codec is intended to use.
149+ *
150+ * @return the original {@link SegmentInfoFormat} used by this codec
151+ */
152+ protected abstract SegmentInfoFormat originalSegmentInfoFormat ();
153+
154+ /**
155+ * Returns the original {@link FieldInfosFormat} used by this codec.
156+ * This method should be implemented by subclasses to provide the specific
157+ * {@link FieldInfosFormat} that this codec is intended to use.
158+ *
159+ * @return the original {@link FieldInfosFormat} used by this codec
160+ */
161+ protected abstract FieldInfosFormat originalFieldInfosFormat ();
162+
91163 // mark all fields as no term vectors, no norms, no payloads, and no vectors.
92164 private static FieldInfos filterFields (FieldInfos fieldInfos ) {
93165 List <FieldInfo > fieldInfoCopy = new ArrayList <>(fieldInfos .size ());
@@ -119,15 +191,14 @@ private static FieldInfos filterFields(FieldInfos fieldInfos) {
119191 }
120192
121193 public static SegmentInfo wrap (SegmentInfo segmentInfo ) {
122- // special handling for Lucene70Codec (which is currently bundled with Lucene)
123- // Use BWCLucene70Codec instead as that one extends BWCCodec (similar to all other older codecs)
124- final Codec codec = segmentInfo .getCodec () instanceof Lucene70Codec ? new BWCLucene70Codec () : segmentInfo .getCodec ();
194+ Codec codec = getBackwardCompatibleCodec (segmentInfo .getCodec ());
195+
125196 final SegmentInfo segmentInfo1 = new SegmentInfo (
126197 segmentInfo .dir ,
127198 // Use Version.LATEST instead of original version, otherwise SegmentCommitInfo will bark when processing (N-1 limitation)
128199 // TODO: perhaps store the original version information in attributes so that we can retrieve it later when needed?
129- org . apache . lucene . util . Version .LATEST ,
130- org . apache . lucene . util . Version .LATEST ,
200+ Version .LATEST ,
201+ Version .LATEST ,
131202 segmentInfo .name ,
132203 segmentInfo .maxDoc (),
133204 segmentInfo .getUseCompoundFile (),
@@ -142,6 +213,28 @@ public static SegmentInfo wrap(SegmentInfo segmentInfo) {
142213 return segmentInfo1 ;
143214 }
144215
216+ /**
217+ * Returns a backward-compatible codec for the given codec. If the codec is one of the known Lucene 8.x codecs,
218+ * it returns a corresponding read-only backward-compatible codec. Otherwise, it returns the original codec.
219+ * Lucene 8.x codecs are still shipped with the current version of Lucene.
220+ * Earlier codecs we are providing directly they will also be read-only backward-compatible, but they don't require the renaming.
221+ *
222+ * This switch is only for indices created in ES 6.x, later written into in ES 7.x (Lucene 8.x). Indices created
223+ * in ES 7.x can be read directly by ES if marked read-only, without going through archive indices.
224+ */
225+ private static Codec getBackwardCompatibleCodec (Codec codec ) {
226+ if (codec == null ) return null ;
227+
228+ return switch (codec .getClass ().getSimpleName ()) {
229+ case "Lucene70Codec" -> new BWCLucene70Codec ();
230+ case "Lucene80Codec" -> new BWCLucene80Codec ();
231+ case "Lucene84Codec" -> new BWCLucene84Codec ();
232+ case "Lucene86Codec" -> new BWCLucene86Codec ();
233+ case "Lucene87Codec" -> new BWCLucene87Codec ();
234+ default -> codec ;
235+ };
236+ }
237+
145238 /**
146239 * In-memory postings format that shows no postings available.
147240 */
0 commit comments