Elasticsearch wildcard query in Java - find all matching fields and replace

602 views Asked by At

I want to update all path fields starting with "example/one".

Map<String, Object> parameters = new HashMap<>();
parameters.put("old", "example/one");
parameters.put("new", "new/example");
    
UpdateByQueryRequest request = new UpdateByQueryRequest(index)
        .setDocTypes(type)
        .setScript(new Script(ScriptType.INLINE,
                "painless",
                "ctx._source.path = ctx._source.path.replace(params.old, params.new);",
                parameters))
        .setQuery(QueryBuilders.wildcardQuery("path.tree", "example/one*"));

client.updateByQuery(request, RequestOptions.DEFAULT);

It's not working (no update, no errors - tried a prefixQuery, same). The following query however is updating the matching documents (Postman).

POST my_index/_update_by_query
{
    "script": {
        "lang": "painless",
        "inline": "ctx._source.path = ctx._source.path.replace(\"example/one\", \"new/example\")"
    },
    "query": {
        "wildcard": {
            "path.tree": {
                "value: "example/one*",
                "boost": 1.0,
                "rewrite": "constant_score"
            }
        }
    }
}

What am I missing? The Path hierarchy tokenizer is used on the field path.
Your help is much needed.

PS: I can't upgrade to a newer version of elasticsearch.

1

There are 1 answers

0
Rahi On BEST ANSWER

When testing the solution, I first thought it was related to the custom analyser used on the path field. But it was quickly discarded as I was getting the expected result via Postman.

I finally decided to go with a 'two steps' solution (couldn't use the update by query API). First search for all matching documents, then perform a bulk update.

NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.wildcardQuery("path.tree", "example/one*"))
                .withSourceFilter(new FetchSourceFilter(new String[]{"_id", "path"}, null))
                .build();
        List<MyClass> result = elasticsearchRestTemplate.queryForList(query, MyClass.class);
        if(!CollectionUtils.isEmpty(result)) {
            Map<String, Object> parameters = new HashMap<>();
            parameters.put("old", "example/one");
            parameters.put("new", "new/example");
            Script script = new Script(ScriptType.INLINE,
                    "painless",
                    "ctx._source.path = ctx._source.path.replace(params.old, params.new)",
                    parameters);
            BulkRequest request = new BulkRequest();
            for (MyClass myClass : result) {
                request.add(new UpdateRequest(index, type, myClass.getId()).script(script));
            }
            client.bulk(request, RequestOptions.DEFAULT);
        }

UPDATE

Turns out setting the type in the request was the problem.

UpdateByQueryRequest request = new UpdateByQueryRequest(index)
        .setDocTypes(type) <--------------- Remove
        .....