Permalink
Browse files

Inner fields of arbitrary depth are now supported for index fields. F…

…ixed two NullPointerExceptions by skipping cases where the attribute or matcher of an index field do not exist in the model.
  • Loading branch information...
davemoore- committed Apr 9, 2018
1 parent 19f7047 commit 75d4fb878101c327c8f8424ae87d6180ba956fdc
Showing with 45 additions and 13 deletions.
  1. +20 −0 src/main/java/io/zentity/model/IndexField.java
  2. +25 −13 src/main/java/io/zentity/resolution/Job.java
@@ -13,23 +13,28 @@
Arrays.asList("attribute")
);
private static final Pattern REGEX_EMPTY = Pattern.compile("^\\s*$");
private static final Pattern REGEX_PERIOD = Pattern.compile("\\.");
private final String index;
private final String name;
private String path;
private String pathParent;
private String attribute;
private String matcher;
public IndexField(String index, String name, JsonNode json) throws ValidationException {
validateName(name);
this.index = index;
this.name = name;
this.nameToPaths(name);
this.deserialize(json);
}
public IndexField(String index, String name, String json) throws ValidationException, IOException {
validateName(name);
this.index = index;
this.name = name;
this.nameToPaths(name);
this.deserialize(json);
}
@@ -41,6 +46,14 @@ public String name() {
return this.name;
}
public String path() {
return this.path;
}
public String pathParent() {
return this.pathParent;
}
public String attribute() {
return this.attribute;
}
@@ -59,6 +72,13 @@ public void matcher(JsonNode value) throws ValidationException {
this.matcher = value.textValue();
}
private void nameToPaths(String name) {
String[] parts = REGEX_PERIOD.split(name);
this.path = "/" + String.join("/", parts);
if (parts.length > 1)
this.pathParent = "/" + String.join("/", Arrays.copyOf(parts, parts.length - 1));
}
private void validateName(String value) throws ValidationException {
if (REGEX_EMPTY.matcher(value).matches())
throw new ValidationException("'indices." + this.index + "' has a field with an empty name.");
@@ -169,6 +169,15 @@ private String jsonStringFormat(String value) {
return jsonStringQuote(jsonStringEscape(value));
}
private boolean indexFieldHasMatcher(String indexName, String indexFieldName) {
String matcherName = this.model.indices().get(indexName).fields().get(indexFieldName).matcher();
if (matcherName == null)
return false;
if (this.model.matchers().get(matcherName) == null)
return false;
return true;
}
/**
* Determine if we can construct a query for a given resolver on a given index with a given input.
* Each attribute of the resolver must be mapped to a field of the index and have a matcher defined for it.
@@ -199,7 +208,7 @@ private boolean canQuery(String indexName, String resolverName) {
// The index field must have a matcher defined for it.
boolean hasMatcher = false;
for (String indexFieldName : this.model.indices().get(indexName).attributeIndexFieldsMap().get(attributeName).keySet()) {
if (this.model.indices().get(indexName).fields().get(indexFieldName).matcher() != null) {
if (this.indexFieldHasMatcher(indexName, indexFieldName)) {
hasMatcher = true;
break;
}
@@ -280,8 +289,7 @@ private void traverse() throws IOException, ValidationException {
for (String indexFieldName : this.model.indices().get(indexName).attributeIndexFieldsMap().get(attributeName).keySet()) {
// Can we use this index field?
boolean hasMatcher = this.model.indices().get(indexName).fields().get(indexFieldName).matcher() != null;
if (!hasMatcher)
if (!this.indexFieldHasMatcher(indexName, indexFieldName))
continue;
// Construct a clause for each input value for this attribute.
@@ -381,20 +389,24 @@ private void traverse() throws IOException, ValidationException {
TreeMap<String, JsonNode> docAttributes = new TreeMap<>();
for (String indexFieldName : this.model.indices().get(indexName).fields().keySet()) {
String attributeName = this.model.indices().get(indexName).fields().get(indexFieldName).attribute();
if (this.model.attributes().get(attributeName) == null)
continue;
String attributeType = this.model.attributes().get(attributeName).type();
if (!nextInputAttributes.containsKey(attributeName))
nextInputAttributes.put(attributeName, new HashSet<>());
// The index field name might not refer to the _source property.
// If it's not in the _source, remove the last part of the index field name from the dot notation.
// Index field names can reference multi-fields, which are not returned in the _source.
if (!nextInputAttributes.containsKey(attributeName))
nextInputAttributes.put(attributeName, new HashSet<>());
if (!doc.get("_source").has(indexFieldName))
indexFieldName = indexFieldName.split("\\.")[0];
if (doc.get("_source").has(indexFieldName)) {
JsonNode valueNode = doc.get("_source").get(indexFieldName);
docAttributes.put(attributeName, valueNode);
Object value = Attribute.convertType(attributeType, valueNode);
nextInputAttributes.get(attributeName).add(value);
}
String path = this.model.indices().get(indexName).fields().get(indexFieldName).path();
String pathParent = this.model.indices().get(indexName).fields().get(indexFieldName).pathParent();
JsonNode valueNode = doc.get("_source").at(path);
if (valueNode.isMissingNode())
valueNode = doc.get("_source").at(pathParent);
if (valueNode.isMissingNode())
continue;
docAttributes.put(attributeName, valueNode);
Object value = Attribute.convertType(attributeType, valueNode);
nextInputAttributes.get(attributeName).add(value);
}
// Modify doc metadata.

0 comments on commit 75d4fb8

Please sign in to comment.