Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit 15f9343

Browse files
authored
Fix incorrect field encodings for fields from mappings (but missing from JSON) (#1050)
In the `CREATE TABLE`, Quesma includes fields we got from `PUT /:index/_mapping` (but are missing from the JSON). This code path incorrectly computed field encodings - used the encoded field name in the comment instead of the field name before encoding. Fix the issue by using the `reverseMap` (field name before encoding) in that code path. Fixes #1045
1 parent b5628e2 commit 15f9343

File tree

5 files changed

+76
-7
lines changed

5 files changed

+76
-7
lines changed

ci/it/configs/quesma-ingest.yml.template

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ processors:
9292
nested_test:
9393
target:
9494
- my-clickhouse-instance
95+
encodings_test:
96+
target:
97+
- my-clickhouse-instance
9598
"*":
9699
target:
97100
- my-minimal-elasticsearch
@@ -167,6 +170,9 @@ processors:
167170
nested_test:
168171
target:
169172
- my-clickhouse-instance
173+
encodings_test:
174+
target:
175+
- my-clickhouse-instance
170176
"*":
171177
target:
172178
- my-minimal-elasticsearch

ci/it/testcases/base.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,27 @@ func (tc *IntegrationTestcaseBase) FetchClickHouseColumns(ctx context.Context, t
135135
return result, nil
136136
}
137137

138+
func (tc *IntegrationTestcaseBase) FetchClickHouseComments(ctx context.Context, tableName string) (map[string]string, error) {
139+
rows, err := tc.ExecuteClickHouseQuery(ctx, fmt.Sprintf("SELECT name, comment FROM system.columns WHERE table = '%s'", tableName))
140+
if err != nil {
141+
return nil, err
142+
}
143+
defer rows.Close()
144+
145+
result := make(map[string]string)
146+
for rows.Next() {
147+
var name, comment string
148+
if err := rows.Scan(&name, &comment); err != nil {
149+
return nil, err
150+
}
151+
result[name] = comment
152+
}
153+
if err := rows.Err(); err != nil {
154+
return nil, err
155+
}
156+
return result, nil
157+
}
158+
138159
func (tc *IntegrationTestcaseBase) RequestToQuesma(ctx context.Context, t *testing.T, method, uri string, requestBody []byte) (*http.Response, []byte) {
139160
endpoint := tc.getQuesmaEndpoint()
140161
resp, err := tc.doRequest(ctx, method, endpoint+uri, requestBody, nil)

ci/it/testcases/test_ingest.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func (a *IngestTestcase) RunTests(ctx context.Context, t *testing.T) error {
4343
t.Run("test kibana_sample_data_ecommerce ingest to ClickHouse (with PUT mapping)", func(t *testing.T) { a.testKibanaSampleEcommerceIngestWithMappingToClickHouse(ctx, t) })
4444
t.Run("test ignored fields", func(t *testing.T) { a.testIgnoredFields(ctx, t) })
4545
t.Run("test nested fields", func(t *testing.T) { a.testNestedFields(ctx, t) })
46+
t.Run("test field encodings (mappings bug)", func(t *testing.T) { a.testFieldEncodingsMappingsBug(ctx, t) })
4647
return nil
4748
}
4849

@@ -608,3 +609,42 @@ func (it *IngestTestcase) testNestedFields(ctx context.Context, t *testing.T) {
608609

609610
assert.False(t, rows.Next())
610611
}
612+
613+
// Reproducer for issue #1045
614+
func (a *IngestTestcase) testFieldEncodingsMappingsBug(ctx context.Context, t *testing.T) {
615+
resp, _ := a.RequestToQuesma(ctx, t, "PUT", "/encodings_test", []byte(`
616+
{
617+
"mappings": {
618+
"properties": {
619+
"Field1": {
620+
"type": "text"
621+
},
622+
"Field2": {
623+
"type": "text"
624+
}
625+
}
626+
},
627+
"settings": {
628+
"index": {}
629+
}
630+
}`))
631+
assert.Equal(t, http.StatusOK, resp.StatusCode)
632+
633+
resp, _ = a.RequestToQuesma(ctx, t, "POST", "/encodings_test/_doc", []byte(`
634+
{
635+
"Field1": "abc"
636+
}`))
637+
assert.Equal(t, http.StatusOK, resp.StatusCode)
638+
639+
resp, _ = a.RequestToQuesma(ctx, t, "POST", "/encodings_test/_doc", []byte(`
640+
{
641+
"Field2": "cde"
642+
}`))
643+
assert.Equal(t, http.StatusOK, resp.StatusCode)
644+
645+
comments, err := a.FetchClickHouseComments(ctx, "encodings_test")
646+
assert.NoError(t, err, "error fetching clickhouse comments")
647+
648+
assert.Equal(t, "quesmaMetadataV1:fieldName=Field1", comments["field1"])
649+
assert.Equal(t, "quesmaMetadataV1:fieldName=Field2", comments["field2"])
650+
}

quesma/ingest/insert_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ func TestCreateTableIfSomeFieldsExistsInSchemaAlready(t *testing.T) {
382382
{"new_field": "bar"},
383383
},
384384
expectedStatements: []string{
385-
`CREATE TABLE IF NOT EXISTS "test_index" ( "@timestamp" DateTime64(3) DEFAULT now64(), "attributes_values" Map(String,String), "attributes_metadata" Map(String,String), "new_field" Nullable(String) COMMENT 'quesmaMetadataV1:fieldName=new_field', "schema_field" Nullable(String) COMMENT 'quesmaMetadataV1:fieldName=schema_field', ) ENGINE = MergeTree ORDER BY ("@timestamp") COMMENT 'created by Quesma'`,
385+
`CREATE TABLE IF NOT EXISTS "test_index" ( "@timestamp" DateTime64(3) DEFAULT now64(), "attributes_values" Map(String,String), "attributes_metadata" Map(String,String), "new_field" Nullable(String) COMMENT 'quesmaMetadataV1:fieldName=new_field', "nested_field" Nullable(String) COMMENT 'quesmaMetadataV1:fieldName=nested.field', ) ENGINE = MergeTree ORDER BY ("@timestamp") COMMENT 'created by Quesma'`,
386386
`INSERT INTO "test_index" FORMAT JSONEachRow {"new_field":"bar"}`,
387387
},
388388
},
@@ -402,9 +402,9 @@ func TestCreateTableIfSomeFieldsExistsInSchemaAlready(t *testing.T) {
402402
indexSchema := schema.Schema{
403403
ExistsInDataSource: false,
404404
Fields: map[schema.FieldName]schema.Field{
405-
"schema_field": {
406-
PropertyName: "schema_field",
407-
InternalPropertyName: "schema_field",
405+
"nested.field": {
406+
PropertyName: "nested.field",
407+
InternalPropertyName: "nested_field",
408408
InternalPropertyType: "String",
409409
Type: schema.QuesmaTypeKeyword},
410410
},
@@ -431,7 +431,7 @@ func TestCreateTableIfSomeFieldsExistsInSchemaAlready(t *testing.T) {
431431
resolver.Decisions["test_index"] = decision
432432

433433
schemaRegistry.FieldEncodings = make(map[schema.FieldEncodingKey]schema.EncodedFieldName)
434-
schemaRegistry.FieldEncodings[schema.FieldEncodingKey{TableName: indexName, FieldName: "schema_field"}] = "schema_field"
434+
schemaRegistry.FieldEncodings[schema.FieldEncodingKey{TableName: indexName, FieldName: "nested.field"}] = "nested_field"
435435

436436
ingest := newIngestProcessorWithEmptyTableMap(tables, quesmaConfig)
437437
ingest.chDb = db

quesma/ingest/parser.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,17 @@ func columnsToString(columnsFromJson []CreateTableEntry,
6767
}
6868

6969
// There might be some columns from schema which were not present in the JSON
70-
for propertyName, column := range columnsFromSchema {
70+
for _, column := range columnsFromSchema {
7171
if first {
7272
first = false
7373
} else {
7474
result.WriteString(",\n")
7575
}
7676

77+
propertyName := reverseMap[schema.EncodedFieldName(column.ClickHouseColumnName)].FieldName
78+
7779
columnMetadata := comment_metadata.NewCommentMetadata()
78-
columnMetadata.Values[comment_metadata.ElasticFieldName] = string(propertyName)
80+
columnMetadata.Values[comment_metadata.ElasticFieldName] = propertyName
7981
comment := columnMetadata.Marshall()
8082

8183
result.WriteString(util.Indent(1))

0 commit comments

Comments
 (0)