elasticgraph-indexer 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a8d580572ec508d9df0131448f19398a5850aaee3cd1e36b4530be67bee190f
4
- data.tar.gz: 7db60416bac8d71edad120569e8abfe55e2884b6844d140109e485b8c9d66d10
3
+ metadata.gz: '0308b6d8490bd282e073ec4ca59840aa95fb5fa0617aeeb0f6abf8c43d767a0b'
4
+ data.tar.gz: f8fa720ceb8cfed471671a155069dbddd9857ea91cd6a23af787ead0e7e221fc
5
5
  SHA512:
6
- metadata.gz: 14b344d1591976df42dd53257a03911e158f9913974c7c2e606c8ea1222989a6552154f615606d0447e97aebef4097f6710600a0af49f453e821c519c89ee146
7
- data.tar.gz: 45d6e1a8c27040378857d7b0c7a7411b669c9f9c6e4ba31ee7e3307cfd71f48780c842e1f505d4d3b19e1c63fdfdcdee2db2dfb30b9e5feb40a122796a991dbe
6
+ metadata.gz: 70d14ee0336b0d99c2c470b6acddd04e6d7c34d7ab664bea6bf9b87a1a140fa81826feca1d69f437105f833bed0a1ea069fe08b5841b524727cdfbc348851542
7
+ data.tar.gz: eec5e893caf16c8bcb888f2bba16122f45b52a006b3350032a33598d42f8384b5cf683a79d0e88d7481b2efb27cbf341b4c12f17fc4843e392ef874803aeef81
@@ -10,6 +10,7 @@ require "elastic_graph/constants"
10
10
  require "elastic_graph/errors"
11
11
  require "elastic_graph/indexer/event_id"
12
12
  require "elastic_graph/indexer/indexing_failures_error"
13
+ require "elastic_graph/support/opaque_id"
13
14
  require "elastic_graph/support/threading"
14
15
 
15
16
  module ElasticGraph
@@ -188,7 +189,14 @@ module ElasticGraph
188
189
  ]
189
190
  end
190
191
 
191
- client.msearch(body: body)
192
+ headers = {
193
+ OPAQUE_ID_HEADER => Support::OpaqueID.build_header(opaque_id_parts_for_source_event_versions(ops))
194
+ }.compact # : ::Hash[::String, ::String]
195
+
196
+ client.msearch(
197
+ body: body,
198
+ headers: headers
199
+ )
192
200
  else
193
201
  # The named client doesn't exist, so we don't have any versions for the docs.
194
202
  {"responses" => ops.map { |op| {"hits" => {"hits" => _ = []}} }}
@@ -256,6 +264,22 @@ module ElasticGraph
256
264
  "for document versions:\n\n#{failures.join("\n")}"
257
265
  end
258
266
  end
267
+
268
+ private
269
+
270
+ def opaque_id_parts_for_source_event_versions(operations)
271
+ type_counts = operations
272
+ .group_by { |op| op.event.fetch("type") }
273
+ .sort_by(&:first)
274
+ .map { |type_name, ops| "#{type_name}:#{ops.size}" }
275
+
276
+ [
277
+ "elasticgraph-indexer",
278
+ "purpose=source_event_versions",
279
+ "operation_count=#{operations.size}",
280
+ "type_counts=#{type_counts.join(",")}"
281
+ ]
282
+ end
259
283
  end
260
284
  end
261
285
  end
@@ -27,7 +27,11 @@ module ElasticGraph
27
27
  update_target:,
28
28
  destination_index_mapping:
29
29
  )
30
- prepared_record = record_preparer.prepare_for_index(event["type"], event["record"] || {"id" => event["id"]})
30
+ prepared_record = record_preparer.prepare_for_index(
31
+ event["type"],
32
+ event["record"] || {"id" => event["id"]},
33
+ destination_index_mapping.fetch("properties")
34
+ )
31
35
 
32
36
  Support::HashUtil
33
37
  .fetch_leaf_values_at_path(prepared_record, update_target.id_source.split("."))
@@ -50,10 +50,6 @@ module ElasticGraph
50
50
  {} # : ::Hash[::String, untyped]
51
51
  end # : ::Hash[::String, untyped]
52
52
 
53
- required_fields = type_def.fetch("required") do
54
- [] # : ::Array[::String]
55
- end # : ::Array[::String]
56
-
57
53
  eg_meta_by_field_name = properties.filter_map do |prop_name, prop|
58
54
  eg_meta = prop["ElasticGraph"]
59
55
  [prop_name, eg_meta] if eg_meta
@@ -61,7 +57,6 @@ module ElasticGraph
61
57
 
62
58
  TypeMetadata.new(
63
59
  name: type,
64
- requires_typename: required_fields.include?("__typename"),
65
60
  eg_meta_by_field_name: eg_meta_by_field_name
66
61
  )
67
62
  end
@@ -76,8 +71,8 @@ module ElasticGraph
76
71
  # still build operations for it, and the operations require a `RecordPreparer`, but we do
77
72
  # not send them to the datastore.
78
73
  module Identity
79
- def self.prepare_for_index(type_name, record)
80
- record
74
+ def self.prepare_for_index(type_name, value, mapping_properties)
75
+ value
81
76
  end
82
77
  end
83
78
 
@@ -86,10 +81,6 @@ module ElasticGraph
86
81
  @eg_meta_by_field_name_by_concrete_type = type_metas.to_h do |meta|
87
82
  [meta.name, meta.eg_meta_by_field_name]
88
83
  end
89
-
90
- @types_requiring_typename = type_metas.filter_map do |meta|
91
- meta.name if meta.requires_typename
92
- end.to_set
93
84
  end
94
85
 
95
86
  # Prepares the given payload for being indexed into the named index.
@@ -104,27 +95,21 @@ module ElasticGraph
104
95
  # the set union of fields and this will take care of dropping any unsupported
105
96
  # fields before we attempt to index the record.
106
97
  #
107
- # Note: this method does not mutate the given `record`. Instead it returns a
98
+ # Note: this method does not mutate the given `value`. Instead it returns a
108
99
  # copy with any updates applied to it.
109
- def prepare_for_index(type_name, record)
110
- prepare_value_for_indexing(record, type_name)
111
- end
112
-
113
- private
114
-
115
- def prepare_value_for_indexing(value, type_name)
100
+ def prepare_for_index(type_name, value, mapping_properties)
116
101
  type_name = type_name.delete_suffix("!")
117
102
 
118
- return nil if value.nil?
103
+ return (_ = nil) if value.nil? # Steep 2.0 narrows to nil here but can't see it satisfies T
119
104
 
120
105
  if (preparer = @indexing_preparer_by_scalar_type_name[type_name])
121
106
  return (_ = preparer).prepare_for_indexing(value)
122
107
  end
123
108
 
124
- case value
109
+ _ = case value # Steep 2.0 can't narrow generic T through case/when branches
125
110
  when ::Array
126
111
  element_type_name = type_name.delete_prefix("[").delete_suffix("]")
127
- value.map { |v| prepare_value_for_indexing(v, element_type_name) }
112
+ value.map { |v| prepare_for_index(element_type_name, v, mapping_properties) }
128
113
  when ::Hash
129
114
  # `@eg_meta_by_field_name_by_concrete_type` does not have abstract types in it (e.g. type unions).
130
115
  # Instead, it'll have each concrete subtype in it.
@@ -133,15 +118,30 @@ module ElasticGraph
133
118
  # what the concrete subtype is. `__typename` is required on abstract types and indicates that.
134
119
  eg_meta_by_field_name = @eg_meta_by_field_name_by_concrete_type.fetch(value["__typename"] || type_name)
135
120
 
136
- value.filter_map do |field_name, field_value|
121
+ # We only want to consider __typename if it's in the per-record mapping in order to determine
122
+ # whether __typename is required on records. When it's a constant_keyword it exists at the index
123
+ # level and therefore should be ignored for this purpose.
124
+ typename_type = mapping_properties&.dig("__typename", "type")
125
+ typename_in_record_mapping = typename_type && typename_type != "constant_keyword"
126
+
127
+ prepared_fields = value.filter_map do |field_name, field_value|
137
128
  if field_name == "__typename"
138
- # We only want to include __typename if it we're dealing with a type that requires it.
139
- # (This is the case for an abstract type, so it can differentiate between which subtype we have
140
- [field_name, field_value] if @types_requiring_typename.include?(type_name)
129
+ # Only include __typename if the index mapping has it at this position.
130
+ [field_name, field_value] if typename_in_record_mapping
141
131
  elsif (eg_meta = eg_meta_by_field_name[field_name])
142
- [eg_meta.fetch("nameInIndex"), prepare_value_for_indexing(field_value, eg_meta.fetch("type"))]
132
+ name_in_index = eg_meta.fetch("nameInIndex")
133
+ nested_mapping_properties = mapping_properties&.dig(name_in_index, "properties")
134
+ [name_in_index, prepare_for_index(eg_meta.fetch("type"), field_value, nested_mapping_properties)]
143
135
  end
144
136
  end.to_h
137
+
138
+ # Inject __typename if the mapping requires it but it's absent from the record
139
+ # (e.g. for a concrete type indexed in a mixed-type index).
140
+ if typename_in_record_mapping && !value.key?("__typename")
141
+ prepared_fields["__typename"] = type_name
142
+ end
143
+
144
+ prepared_fields
145
145
  else
146
146
  # We won't have a registered preparer for enum types, since those aren't dumped in
147
147
  # runtime metadata `scalar_types_by_name`, and we can just return the value as-is in
@@ -153,8 +153,6 @@ module ElasticGraph
153
153
  TypeMetadata = ::Data.define(
154
154
  # The name of the type this metadata object is for.
155
155
  :name,
156
- # Indicates if this type requires a `__typename` field.
157
- :requires_typename,
158
156
  # The per-field ElasticGraph metadata, keyed by field name.
159
157
  :eg_meta_by_field_name
160
158
  )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticgraph-indexer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Myron Marston
@@ -17,42 +17,42 @@ dependencies:
17
17
  requirements:
18
18
  - - '='
19
19
  - !ruby/object:Gem::Version
20
- version: 1.1.0
20
+ version: 1.2.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - '='
26
26
  - !ruby/object:Gem::Version
27
- version: 1.1.0
27
+ version: 1.2.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: elasticgraph-schema_artifacts
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: 1.1.0
34
+ version: 1.2.0
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - '='
40
40
  - !ruby/object:Gem::Version
41
- version: 1.1.0
41
+ version: 1.2.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: elasticgraph-support
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - '='
47
47
  - !ruby/object:Gem::Version
48
- version: 1.1.0
48
+ version: 1.2.0
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - '='
54
54
  - !ruby/object:Gem::Version
55
- version: 1.1.0
55
+ version: 1.2.0
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: hashdiff
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -79,56 +79,56 @@ dependencies:
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 1.1.0
82
+ version: 1.2.0
83
83
  type: :development
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: 1.1.0
89
+ version: 1.2.0
90
90
  - !ruby/object:Gem::Dependency
91
91
  name: elasticgraph-elasticsearch
92
92
  requirement: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 1.1.0
96
+ version: 1.2.0
97
97
  type: :development
98
98
  prerelease: false
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - '='
102
102
  - !ruby/object:Gem::Version
103
- version: 1.1.0
103
+ version: 1.2.0
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: elasticgraph-opensearch
106
106
  requirement: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
- version: 1.1.0
110
+ version: 1.2.0
111
111
  type: :development
112
112
  prerelease: false
113
113
  version_requirements: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - '='
116
116
  - !ruby/object:Gem::Version
117
- version: 1.1.0
117
+ version: 1.2.0
118
118
  - !ruby/object:Gem::Dependency
119
119
  name: elasticgraph-schema_definition
120
120
  requirement: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
- version: 1.1.0
124
+ version: 1.2.0
125
125
  type: :development
126
126
  prerelease: false
127
127
  version_requirements: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - '='
130
130
  - !ruby/object:Gem::Version
131
- version: 1.1.0
131
+ version: 1.2.0
132
132
  email:
133
133
  - myron@squareup.com
134
134
  executables: []
@@ -161,10 +161,10 @@ licenses:
161
161
  - MIT
162
162
  metadata:
163
163
  bug_tracker_uri: https://github.com/block/elasticgraph/issues
164
- changelog_uri: https://github.com/block/elasticgraph/releases/tag/v1.1.0
165
- documentation_uri: https://block.github.io/elasticgraph/api-docs/v1.1.0/
164
+ changelog_uri: https://github.com/block/elasticgraph/releases/tag/v1.2.0
165
+ documentation_uri: https://block.github.io/elasticgraph/api-docs/v1.2.0/
166
166
  homepage_uri: https://block.github.io/elasticgraph/
167
- source_code_uri: https://github.com/block/elasticgraph/tree/v1.1.0/elasticgraph-indexer
167
+ source_code_uri: https://github.com/block/elasticgraph/tree/v1.2.0/elasticgraph-indexer
168
168
  gem_category: core
169
169
  rdoc_options: []
170
170
  require_paths:
@@ -183,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
183
  - !ruby/object:Gem::Version
184
184
  version: '0'
185
185
  requirements: []
186
- rubygems_version: 4.0.3
186
+ rubygems_version: 4.0.6
187
187
  specification_version: 4
188
188
  summary: Indexes ElasticGraph data into a datastore.
189
189
  test_files: []