Skip to content

Commit c937a09

Browse files
authored
Script: fields API for x-pack version, doc version, seq no, mumur3 (#81476)
Adds scripting fields API support the rest of the long fields: * [`_version`](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-versioning) - `VersionDocValuesField` * [`_seq_no`](https://www.elastic.co/guide/en/elasticsearch/reference/master/optimistic-concurrency-control.html) - `SeqNoDocValuesField` * [`murmur3`](https://www.elastic.co/guide/en/elasticsearch/plugins/current/mapper-murmur3-usage.html) - `Murmur3DocValueField` * Added Painless support to the murmur3 mapper plugin. All `SortedNumericDocValues` that are interpreted as longs are now subclasses of `AbstractLongDocValuesField`, including murmur, doc version and seq no above as well as `LongDocValuesField` and `UnsignedLongDocValuesField` Also adds: * [x-pack's version](https://www.elastic.co/guide/en/elasticsearch/reference/master/version.html) - `VersionStringDocValuesField` * Created new `Version` value type as a location for future helpers for comparing versions. * Implements `toString` for the expected representation of the version * Implements `asString(String)` and `asString(int, String)`, `asStrings()` converters on field. Refs: #79105
1 parent e5efade commit c937a09

File tree

28 files changed

+691
-346
lines changed

28 files changed

+691
-346
lines changed

docs/changelog/81476.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 81476
2+
summary: "Script: fields API for x-pack version, doc version, seq no, mumur3"
3+
area: Infra/Scripting
4+
type: enhancement
5+
issues: []

modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.script.fields.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,16 @@ class org.elasticsearch.script.field.IpDocValuesField @dynamic_type {
100100
String asString(String)
101101
String asString(int, String)
102102
}
103+
104+
class org.elasticsearch.script.field.AbstractLongDocValuesField @dynamic_type {
105+
long get(long)
106+
long get(int, long)
107+
}
108+
109+
# subclass of AbstractLongDocValuesField
110+
class org.elasticsearch.script.field.SeqNoDocValuesField @dynamic_type {
111+
}
112+
113+
# subclass of AbstractLongDocValuesField
114+
class org.elasticsearch.script.field.VersionDocValuesField @dynamic_type {
115+
}

modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/50_script_doc_values.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,3 +1446,81 @@ setup:
14461446
script:
14471447
source: "int value = field('dne').get(1, 1); value"
14481448
- match: { hits.hits.0.fields.field.0: 1 }
1449+
1450+
---
1451+
"version and sequence number":
1452+
- do:
1453+
indices.create:
1454+
index: versiontest
1455+
body:
1456+
settings:
1457+
number_of_shards: 1
1458+
mappings:
1459+
properties:
1460+
keyword:
1461+
type: keyword
1462+
1463+
- do:
1464+
index:
1465+
index: test
1466+
id: 3000
1467+
version: 50
1468+
version_type: external
1469+
body:
1470+
keyword: "3k"
1471+
1472+
- do:
1473+
indices.refresh: {}
1474+
1475+
- do:
1476+
search:
1477+
rest_total_hits_as_int: true
1478+
body:
1479+
query: { term: { _id: 3000 } }
1480+
script_fields:
1481+
ver:
1482+
script:
1483+
source: "field('_version').get(10000)"
1484+
seq:
1485+
script:
1486+
source: "field('_seq_no').get(10000)"
1487+
- match: { hits.hits.0.fields.ver.0: 50 }
1488+
- match: { hits.hits.0.fields.seq.0: 3 }
1489+
1490+
- do:
1491+
index:
1492+
index: test
1493+
id: 3000
1494+
version: 60
1495+
version_type: external
1496+
body:
1497+
keyword: "3k+1"
1498+
- do:
1499+
indices.refresh: {}
1500+
1501+
- do:
1502+
catch: conflict
1503+
index:
1504+
index: test
1505+
id: 3000
1506+
version: 55
1507+
version_type: external
1508+
body:
1509+
keyword: "3k+2"
1510+
- do:
1511+
indices.refresh: {}
1512+
1513+
- do:
1514+
search:
1515+
rest_total_hits_as_int: true
1516+
body:
1517+
query: { term: { _id: 3000 } }
1518+
script_fields:
1519+
ver:
1520+
script:
1521+
source: "field('_version').get(10000)"
1522+
seq:
1523+
script:
1524+
source: "field('_seq_no').get(10000)"
1525+
- match: { hits.hits.0.fields.ver.0: 60 }
1526+
- match: { hits.hits.0.fields.seq.0: 4 }

plugins/mapper-murmur3/build.gradle

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,21 @@ apply plugin: 'elasticsearch.yaml-rest-compat-test'
1111
esplugin {
1212
description 'The Mapper Murmur3 plugin allows to compute hashes of a field\'s values at index-time and to store them in the index.'
1313
classname 'org.elasticsearch.plugin.mapper.MapperMurmur3Plugin'
14+
extendedPlugins = ['lang-painless']
15+
}
16+
17+
dependencies {
18+
compileOnly project(':modules:lang-painless:spi')
19+
testImplementation project(':modules:lang-painless')
1420
}
1521

1622
restResources {
1723
restApi {
1824
include '_common', 'indices', 'index', 'search'
1925
}
2026
}
27+
28+
testClusters.configureEach {
29+
testDistribution = 'DEFAULT'
30+
setting 'xpack.security.enabled', 'false'
31+
}

plugins/mapper-murmur3/src/main/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapper.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@
1212
import org.apache.lucene.document.SortedNumericDocValuesField;
1313
import org.apache.lucene.document.StoredField;
1414
import org.apache.lucene.index.IndexOptions;
15-
import org.apache.lucene.index.SortedNumericDocValues;
1615
import org.apache.lucene.search.Query;
1716
import org.apache.lucene.util.BytesRef;
1817
import org.elasticsearch.common.hash.MurmurHash3;
1918
import org.elasticsearch.index.fielddata.IndexFieldData;
2019
import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType;
21-
import org.elasticsearch.index.fielddata.ScriptDocValues.Longs;
22-
import org.elasticsearch.index.fielddata.ScriptDocValues.LongsSupplier;
2320
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
2421
import org.elasticsearch.index.mapper.DocumentParserContext;
2522
import org.elasticsearch.index.mapper.FieldMapper;
@@ -29,8 +26,7 @@
2926
import org.elasticsearch.index.mapper.TextSearchInfo;
3027
import org.elasticsearch.index.mapper.ValueFetcher;
3128
import org.elasticsearch.index.query.SearchExecutionContext;
32-
import org.elasticsearch.script.field.DelegateDocValuesField;
33-
import org.elasticsearch.script.field.ToScriptField;
29+
import org.elasticsearch.script.field.murmur3.Murmur3DocValueField;
3430
import org.elasticsearch.search.lookup.SearchLookup;
3531

3632
import java.io.IOException;
@@ -84,11 +80,6 @@ public Murmur3FieldMapper build(MapperBuilderContext context) {
8480
// this only exists so a check can be done to match the field type to using murmur3 hashing...
8581
public static class Murmur3FieldType extends MappedFieldType {
8682

87-
public static final ToScriptField<SortedNumericDocValues> TO_SCRIPT_FIELD = (dv, n) -> new DelegateDocValuesField(
88-
new Longs(new LongsSupplier(dv)),
89-
n
90-
);
91-
9283
private Murmur3FieldType(String name, boolean isStored, Map<String, String> meta) {
9384
super(name, false, isStored, true, TextSearchInfo.NONE, meta);
9485
}
@@ -101,7 +92,7 @@ public String typeName() {
10192
@Override
10293
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
10394
failIfNoDocValues();
104-
return new SortedNumericIndexFieldData.Builder(name(), NumericType.LONG, TO_SCRIPT_FIELD);
95+
return new SortedNumericIndexFieldData.Builder(name(), NumericType.LONG, Murmur3DocValueField::new);
10596
}
10697

10798
@Override
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.script.field.murmur3;
10+
11+
import org.apache.lucene.index.SortedNumericDocValues;
12+
import org.elasticsearch.script.field.AbstractLongDocValuesField;
13+
14+
public class Murmur3DocValueField extends AbstractLongDocValuesField {
15+
16+
public Murmur3DocValueField(SortedNumericDocValues input, String name) {
17+
super(input, name);
18+
}
19+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.script.field.murmur3;
10+
11+
import org.elasticsearch.painless.spi.PainlessExtension;
12+
import org.elasticsearch.painless.spi.Whitelist;
13+
import org.elasticsearch.painless.spi.WhitelistLoader;
14+
import org.elasticsearch.script.ScriptContext;
15+
16+
import java.util.HashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
import static java.util.Collections.singletonList;
21+
import static org.elasticsearch.script.ScriptModule.CORE_CONTEXTS;
22+
23+
public class Murmur3PainlessExtension implements PainlessExtension {
24+
25+
private static final Whitelist WHITELIST = WhitelistLoader.loadFromResourceFiles(
26+
Murmur3PainlessExtension.class,
27+
"org.elasticsearch.field.murmur3.txt"
28+
);
29+
30+
@Override
31+
public Map<ScriptContext<?>, List<Whitelist>> getContextWhitelists() {
32+
List<Whitelist> whitelist = singletonList(WHITELIST);
33+
Map<ScriptContext<?>, List<Whitelist>> contextWhitelists = new HashMap<>(CORE_CONTEXTS.size());
34+
for (ScriptContext<?> scriptContext : CORE_CONTEXTS.values()) {
35+
contextWhitelists.put(scriptContext, whitelist);
36+
}
37+
return contextWhitelists;
38+
}
39+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.elasticsearch.script.field.murmur3.Murmur3PainlessExtension
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#
2+
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
# or more contributor license agreements. Licensed under the Elastic License
4+
# 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
# in compliance with, at your election, the Elastic License 2.0 or the Server
6+
# Side Public License, v 1.
7+
#
8+
9+
# subclass of AbstractLongDocValuesField
10+
class org.elasticsearch.script.field.murmur3.Murmur3DocValueField @dynamic_type {
11+
}

plugins/mapper-murmur3/src/yamlRestTest/resources/rest-api-spec/test/mapper_murmur3/10_basic.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# Integration tests for Mapper Murmur3 components
22
#
33

4-
---
5-
"Mapper Murmur3":
6-
4+
setup:
75
- do:
86
indices.create:
97
index: test
@@ -20,6 +18,8 @@
2018
- do:
2119
indices.refresh: {}
2220

21+
---
22+
"Mapper Murmur3":
2323
- do:
2424
search:
2525
rest_total_hits_as_int: true
@@ -60,3 +60,27 @@
6060
body: { "aggs": { "foo_count": { "cardinality": { "field": "foo.hash" } } } }
6161

6262
- match: { aggregations.foo_count.value: 3 }
63+
64+
---
65+
"Mumur3 script fields api":
66+
67+
- do:
68+
index:
69+
index: test
70+
id: 1
71+
body: { "foo": "foo" }
72+
73+
- do:
74+
indices.refresh: {}
75+
76+
- do:
77+
search:
78+
index: test
79+
body:
80+
sort: [ { foo.hash: desc } ]
81+
script_fields:
82+
field:
83+
script:
84+
source: "field('foo.hash').get(10L)"
85+
86+
- match: { hits.hits.0.fields.field.0: -2129773440516405919 }

0 commit comments

Comments
 (0)