support negated set (denied fields) in FieldSubsetReader
Original commit: elastic/x-pack-elasticsearch@0a54417175
This commit is contained in:
parent
dbe189b064
commit
2583e9cd97
|
@ -56,30 +56,33 @@ public final class FieldSubsetReader extends FilterLeafReader {
|
|||
* and so on.
|
||||
* @param in reader to filter
|
||||
* @param fieldNames fields to filter.
|
||||
* @param negate {@code true} if this should be a negative set, meaning set of field names that is denied.
|
||||
*/
|
||||
public static DirectoryReader wrap(DirectoryReader in, Set<String> fieldNames) throws IOException {
|
||||
return new FieldSubsetDirectoryReader(in, fieldNames);
|
||||
public static DirectoryReader wrap(DirectoryReader in, Set<String> fieldNames, boolean negate) throws IOException {
|
||||
return new FieldSubsetDirectoryReader(in, fieldNames, negate);
|
||||
}
|
||||
|
||||
// wraps subreaders with fieldsubsetreaders.
|
||||
static class FieldSubsetDirectoryReader extends FilterDirectoryReader {
|
||||
|
||||
private final Set<String> fieldNames;
|
||||
private final boolean negate;
|
||||
|
||||
FieldSubsetDirectoryReader(DirectoryReader in, final Set<String> fieldNames) throws IOException {
|
||||
FieldSubsetDirectoryReader(DirectoryReader in, Set<String> fieldNames, boolean negate) throws IOException {
|
||||
super(in, new FilterDirectoryReader.SubReaderWrapper() {
|
||||
@Override
|
||||
public LeafReader wrap(LeafReader reader) {
|
||||
return new FieldSubsetReader(reader, fieldNames);
|
||||
return new FieldSubsetReader(reader, fieldNames, negate);
|
||||
}
|
||||
});
|
||||
this.fieldNames = fieldNames;
|
||||
this.negate = negate;
|
||||
verifyNoOtherFieldSubsetDirectoryReaderIsWrapped(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DirectoryReader doWrapDirectoryReader(DirectoryReader in) throws IOException {
|
||||
return new FieldSubsetDirectoryReader(in, fieldNames);
|
||||
return new FieldSubsetDirectoryReader(in, fieldNames, negate);
|
||||
}
|
||||
|
||||
public Set<String> getFieldNames() {
|
||||
|
@ -111,17 +114,23 @@ public final class FieldSubsetReader extends FilterLeafReader {
|
|||
|
||||
/**
|
||||
* Wrap a single segment, exposing a subset of its fields.
|
||||
* @param fields set of field names that should be allowed
|
||||
* @param negate {@code true} if this should be a negative set, meaning set of field names that is denied.
|
||||
*/
|
||||
FieldSubsetReader(LeafReader in, Set<String> fieldNames) {
|
||||
FieldSubsetReader(LeafReader in, Set<String> fields, boolean negate) {
|
||||
super(in);
|
||||
// look at what fields the reader has, and preprocess a subset of them that are allowed
|
||||
ArrayList<FieldInfo> filteredInfos = new ArrayList<>();
|
||||
for (FieldInfo fi : in.getFieldInfos()) {
|
||||
if (fieldNames.contains(fi.name)) {
|
||||
if (fields.contains(fi.name) ^ negate) {
|
||||
filteredInfos.add(fi);
|
||||
}
|
||||
}
|
||||
fieldInfos = new FieldInfos(filteredInfos.toArray(new FieldInfo[filteredInfos.size()]));
|
||||
this.fieldNames = fieldNames.toArray(new String[fieldNames.size()]);
|
||||
fieldNames = new String[filteredInfos.size()];
|
||||
for (int i = 0; i < fieldNames.length; i++) {
|
||||
fieldNames[i] = filteredInfos.get(i).name;
|
||||
}
|
||||
}
|
||||
|
||||
/** returns true if this field is allowed. */
|
||||
|
|
|
@ -144,7 +144,8 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper {
|
|||
allowedFields.addAll(mapperService.simpleMatchToIndexNames(field));
|
||||
}
|
||||
resolveParentChildJoinFields(allowedFields);
|
||||
reader = FieldSubsetReader.wrap(reader, allowedFields);
|
||||
// TODO: support 'denied' fields (pass true as the 3rd parameter in this case)
|
||||
reader = FieldSubsetReader.wrap(reader, allowedFields, false);
|
||||
}
|
||||
|
||||
return reader;
|
||||
|
|
|
@ -97,7 +97,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
|
|||
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(numDocs));
|
||||
assertThat(indexFieldDataCache.topLevelBuilds, equalTo(1));
|
||||
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
|
||||
global = sortedSetDVOrdinalsIndexFieldData.loadGlobal(ir);
|
||||
atomic = global.load(ir.leaves().get(0));
|
||||
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));
|
||||
|
@ -110,7 +110,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
|
|||
assertThat(atomic.getOrdinalsValues().getValueCount(), greaterThanOrEqualTo(1L));
|
||||
}
|
||||
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
|
||||
for (LeafReaderContext context : ir.leaves()) {
|
||||
AtomicOrdinalsFieldData atomic = sortedSetDVOrdinalsIndexFieldData.load(context);
|
||||
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));
|
||||
|
@ -126,7 +126,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
|
|||
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(numDocs));
|
||||
assertThat(indexFieldDataCache.topLevelBuilds, equalTo(1));
|
||||
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
|
||||
global = pagedBytesIndexFieldData.loadGlobal(ir);
|
||||
atomic = global.load(ir.leaves().get(0));
|
||||
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));
|
||||
|
@ -141,7 +141,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
|
|||
}
|
||||
assertThat(indexFieldDataCache.leafLevelBuilds, equalTo(ir.leaves().size()));
|
||||
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
|
||||
for (LeafReaderContext context : ir.leaves()) {
|
||||
AtomicOrdinalsFieldData atomic = pagedBytesIndexFieldData.load(context);
|
||||
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));
|
||||
|
|
|
@ -70,7 +70,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -102,7 +102,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -189,7 +189,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Document d2 = ir.document(0);
|
||||
|
@ -216,7 +216,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Document d2 = ir.document(0);
|
||||
|
@ -243,7 +243,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Document d2 = ir.document(0);
|
||||
|
@ -270,7 +270,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Document d2 = ir.document(0);
|
||||
|
@ -297,7 +297,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Document d2 = ir.document(0);
|
||||
|
@ -324,7 +324,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Document d2 = ir.document(0);
|
||||
|
@ -353,7 +353,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Fields vectors = ir.getTermVectors(0);
|
||||
|
@ -383,7 +383,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -410,7 +410,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -442,7 +442,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -474,7 +474,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -506,7 +506,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -542,7 +542,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -577,7 +577,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -610,7 +610,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
Set<String> fields = new HashSet<>();
|
||||
fields.add("fieldA");
|
||||
fields.add(SourceFieldMapper.NAME);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
Document d2 = ir.document(0);
|
||||
|
@ -641,7 +641,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
Set<String> fields = new HashSet<>();
|
||||
fields.add("fieldA");
|
||||
fields.add(FieldNamesFieldMapper.NAME);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -690,7 +690,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
fields.add("fieldA");
|
||||
fields.add("fieldC");
|
||||
fields.add(FieldNamesFieldMapper.NAME);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only two fields
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -738,7 +738,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
fields.add("fieldA");
|
||||
fields.add("fieldC");
|
||||
fields.add(FieldNamesFieldMapper.NAME);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -774,7 +774,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
Set<String> fields = new HashSet<>();
|
||||
fields.add("fieldA");
|
||||
fields.add(FieldNamesFieldMapper.NAME);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -803,7 +803,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("id");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
assertEquals(2, ir.numDocs());
|
||||
assertEquals(1, ir.leaves().size());
|
||||
|
||||
|
@ -838,7 +838,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldB");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// sees no fields
|
||||
assertNull(ir.getTermVectors(0));
|
||||
|
@ -858,7 +858,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldA");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
|
||||
|
||||
// see no fields
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
|
@ -888,9 +888,9 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
iw.close();
|
||||
|
||||
DirectoryReader directoryReader = DirectoryReader.open(dir);
|
||||
directoryReader = FieldSubsetReader.wrap(directoryReader, Collections.emptySet());
|
||||
directoryReader = FieldSubsetReader.wrap(directoryReader, Collections.emptySet(), false);
|
||||
try {
|
||||
FieldSubsetReader.wrap(directoryReader, Collections.emptySet());
|
||||
FieldSubsetReader.wrap(directoryReader, Collections.emptySet(), false);
|
||||
fail("shouldn't be able to wrap FieldSubsetDirectoryReader twice");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), equalTo("Can't wrap [class org.elasticsearch.xpack.security.authz.accesscontrol" +
|
||||
|
@ -899,4 +899,36 @@ public class FieldSubsetReaderTests extends ESTestCase {
|
|||
directoryReader.close();
|
||||
dir.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* test filtering two string fields, with negated set
|
||||
*/
|
||||
public void testNegative() throws Exception {
|
||||
Directory dir = newDirectory();
|
||||
IndexWriterConfig iwc = new IndexWriterConfig(null);
|
||||
IndexWriter iw = new IndexWriter(dir, iwc);
|
||||
|
||||
// add document with 2 fields
|
||||
Document doc = new Document();
|
||||
doc.add(new StringField("fieldA", "test", Field.Store.NO));
|
||||
doc.add(new StringField("fieldB", "test", Field.Store.NO));
|
||||
iw.addDocument(doc);
|
||||
|
||||
// open reader
|
||||
Set<String> fields = Collections.singleton("fieldB");
|
||||
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, true);
|
||||
|
||||
// see only one field
|
||||
LeafReader segmentReader = ir.leaves().get(0).reader();
|
||||
Set<String> seenFields = new HashSet<>();
|
||||
for (String field : segmentReader.fields()) {
|
||||
seenFields.add(field);
|
||||
}
|
||||
assertEquals(Collections.singleton("fieldA"), seenFields);
|
||||
assertNotNull(segmentReader.terms("fieldA"));
|
||||
assertNull(segmentReader.terms("fieldB"));
|
||||
|
||||
TestUtil.checkReader(ir);
|
||||
IOUtils.close(ir, iw, dir);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue