【问题标题】:Handling Array Indexes When Searching In ElasticSearch在 ElasticSearch 中搜索时处理数组索引
【发布时间】:2022-02-01 19:45:06
【问题描述】:

我的 ES 查询有问题,因为查询字符串中有数组索引,所以它们失败了。发生这种情况是因为我的以下方法。 我将使用以下方法获得的 JSON 请求展平。

private void flattenJsonRequestToMap(String currentPath, JsonNode jsonNode, Map<String, Object> map) {
        if (jsonNode == null || jsonNode.isNull()) {
            map.remove(currentPath);
        } else if (jsonNode.isObject()) {
            ObjectNode objectNode = (ObjectNode) jsonNode;
            Iterator<Map.Entry<String, JsonNode>> iter = objectNode.fields();
            String pathPrefix = currentPath.isEmpty() ? "" : currentPath + ".";

            while (iter.hasNext()) {
                Map.Entry<String, JsonNode> entry = iter.next();
                flattenJsonRequestToMap(pathPrefix + entry.getKey(), entry.getValue(), map);
            }
        } else if (jsonNode.isArray()) {
            ArrayNode arrayNode = (ArrayNode) jsonNode;
            for (int i = 0; i < arrayNode.size(); i++) {
                flattenJsonRequestToMap(currentPath + "[" + i + "]", arrayNode.get(i), map);
            }
        } else if (jsonNode.isValueNode()) {
            ValueNode valueNode = (ValueNode) jsonNode;
            map.put(currentPath, valueNode.asText());
        } else {
            LOGGER.error("JSONNNode unexpected field found during the flattening of JSON request" + jsonNode.asText());
        }
    }

当 Json 请求中有列表时,我的扁平化地图如下所示。

myUserGuid -> user_testuser34_ibzwlm
numberOfOpenings -> 1
managerUserGuids[0] -> test-userYspgF1_S3P6s
accessCategories[0] -> RESTRICTED
employeeUserGuid -> user_user33_m1minh

现在我使用上面的映射通过以下方法构造 ES Query。

public SearchResponse searchForExactDocument(final String indexName, final Map<String, Object> queryMap)
            throws IOException {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryMap.forEach((name, value) -> {
            queryBuilder.must(QueryBuilders.matchPhraseQuery(name, value));
            LOGGER.info("QueryMap key: {} and value: {} ", name, value);
        });
        return this.executeSearch(indexName, queryBuilder);
    }

正如您已经看到的,它最终执行了下面的查询,其中包含数组索引。我的映射结构如下。

{
  name=job,
  type=_doc,
  mappingData={
    properties={
    
      myUserGuid ={
        type=text,
        fields={
          keyword={
            ignore_above=256,
            type=keyword
          }
        }
      },
      numberOfOpenings ={
        type=long
      },
      numOfUsage={
        type=long
      },
      accessCategories ={
        type=text,
        fields={
          keyword={
            ignore_above=256,
            type=keyword
          }
        }
      },
      managerUserGuids ={
        type=text,
        fields={
          keyword={
            ignore_above=256,
            type=keyword
          }
        }
      },
      employeeUserGuid ={
        type=text,
        fields={
          keyword={
            ignore_above=256,
            type=keyword
          }
        }
      }
  }
}

由于名称旁边附加了数组索引,因此查询不会返回任何搜索结果。我该如何解决这个问题?我看到的一个选项是使用展平地图删除数组索引,但是我需要能够使用展平地图构造一个 POJO 对象,该对象具有相关字段的列表。将不胜感激任何意见/建议。提前非常感谢。

【问题讨论】:

    标签: java arrays elasticsearch aws-elasticsearch resthighlevelclient


    【解决方案1】:

    ES 中的列表被处理为一个字段的值很少,所以如果你有"accessCategories": ["foo", "bar"],这个文档将匹配 both "accessCategories": "foo" 和 "accessCategories": "bar" 虽然没有办法制作仅匹配一个(“foo”而不是“bar”)与此数据模式的查询。

    如果您需要处理特定项目,您可以将列表展开为单独的字段accessCategories_0、accessCategories_1 等,尽管 Elasticsearch 对一个索引中的字段总数有限制。

    【讨论】:

    • 我实际上不需要访问特定项目,并希望将这两个列表项目视为“必须”。但是我的布尔查询最终有 accessCategories[0]。 accessCategories[1] 等。我是否需要使用 Java 以某种方式使地图具有 accessCategories -> item1、accessCategories -> item2 来构建查询?
    • 是的,类似于:queryBuilder.must(QueryBuilders.matchPhraseQuery(name, value1)); queryBuilder.must(QueryBuilders.matchPhraseQuery(name, value2));
    猜你喜欢
    • 2022-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-02
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多