Skip to content
代码片段 群组 项目
提交 3b7edbe4 编辑于 作者: Dmitry Gruzd's avatar Dmitry Gruzd 提交者: Terri Chu
浏览文件

Advanced Search: Index label_ids for issues

Changelog: changed
EE: true
上级 51f7be41
No related branches found
No related tags found
无相关合并请求
# frozen_string_literal: true
class AddLabelIdsAndSchemaVersionToIssuesMapping < Elastic::Migration
include Elastic::MigrationUpdateMappingsHelper
private
def index_name
Issue.__elasticsearch__.index_name
end
def new_mappings
{
label_ids: {
type: 'keyword'
},
schema_version: {
type: 'short'
}
}
end
end
# frozen_string_literal: true
class BackfillLabelIdsForIssues < Elastic::Migration
include Elastic::MigrationBackfillHelper
batched!
batch_size 5000
throttle_delay 3.minutes
DOCUMENT_TYPE = Issue
UPDATE_BATCH_SIZE = 100
private
def index_name
DOCUMENT_TYPE.__elasticsearch__.index_name
end
def field_name
# We use schema_version here because it doesn't exist for documents without label_ids
# We can't use label_ids because Elasticsearch treats [] as a non-existent value
:schema_version
end
end
...@@ -31,7 +31,7 @@ def elastic_search(query, options: {}) ...@@ -31,7 +31,7 @@ def elastic_search(query, options: {})
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def preload_indexing_data(relation) def preload_indexing_data(relation)
relation.includes(:issue_assignees, project: [:project_feature, :namespace]) relation.includes(:issue_assignees, :labels, project: [:project_feature, :namespace])
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
......
...@@ -37,6 +37,9 @@ module IssueConfig ...@@ -37,6 +37,9 @@ module IssueConfig
indexes :upvotes, type: :integer indexes :upvotes, type: :integer
indexes :namespace_ancestry, type: :text, index_prefixes: { min_chars: 1, max_chars: 19 } # deprecated indexes :namespace_ancestry, type: :text, index_prefixes: { min_chars: 1, max_chars: 19 } # deprecated
indexes :namespace_ancestry_ids, type: :keyword indexes :namespace_ancestry_ids, type: :keyword
indexes :label_ids, type: :keyword
indexes :schema_version, type: :short
end end
end end
end end
......
...@@ -12,6 +12,10 @@ def as_indexed_json(options = {}) ...@@ -12,6 +12,10 @@ def as_indexed_json(options = {})
data[attr.to_s] = safely_read_attribute_for_elasticsearch(attr) data[attr.to_s] = safely_read_attribute_for_elasticsearch(attr)
end end
# Schema version. The format is Date.today.strftime('%y_%m')
# Please update if you're changing the schema of the document
data['schema_version'] = 22_08
# Load them through the issue_assignees table since calling # Load them through the issue_assignees table since calling
# assignee_ids can't be easily preloaded and does # assignee_ids can't be easily preloaded and does
# unnecessary joins # unnecessary joins
...@@ -23,6 +27,8 @@ def as_indexed_json(options = {}) ...@@ -23,6 +27,8 @@ def as_indexed_json(options = {})
data['upvotes'] = target.upvotes_count data['upvotes'] = target.upvotes_count
data['namespace_ancestry_ids'] = target.namespace_ancestry data['namespace_ancestry_ids'] = target.namespace_ancestry
data['label_ids'] = target.label_ids.map(&:to_s)
data.merge(generic_attributes) data.merge(generic_attributes)
end end
......
# frozen_string_literal: true
require 'spec_helper'
require_relative 'migration_shared_examples'
require File.expand_path('ee/elastic/migrate/20220824123000_add_label_ids_and_schema_version_to_issues_mapping.rb')
RSpec.describe AddLabelIdsAndSchemaVersionToIssuesMapping, :elastic, :sidekiq_inline do
let(:version) { 20220824123000 }
include_examples 'migration adds mapping'
end
# frozen_string_literal: true
require 'spec_helper'
require_relative 'migration_shared_examples'
require File.expand_path('ee/elastic/migrate/20220825102900_backfill_label_ids_for_issues.rb')
RSpec.describe BackfillLabelIdsForIssues, :elastic, :sidekiq_inline do
let(:version) { 20220825102900 }
include_examples 'migration backfills fields' do
let(:label) { create(:label) }
let(:objects) { create_list(:labeled_issue, 3, labels: [label]) }
let(:expected_fields) { { label_ids: [label.id.to_s], schema_version: 22_08 } }
let(:expected_throttle_delay) { 3.minutes }
let(:expected_batch_size) { 5000 }
end
end
# frozen_string_literal: true # frozen_string_literal: true
RSpec.shared_examples 'migration backfills a field' do RSpec.shared_examples 'migration backfills fields' do
let(:migration) { described_class.new(version) } let(:migration) { described_class.new(version) }
let(:klass) { objects.first.class } let(:klass) { objects.first.class }
...@@ -102,20 +102,26 @@ ...@@ -102,20 +102,26 @@
private private
def add_field_for_objects(objects) def add_field_for_objects(objects)
source_script = expected_fields.map do |field_name, _|
"ctx._source['#{field_name}'] = params.#{field_name};"
end.join
script = { script = {
source: "ctx._source['#{field_name}'] = params.#{field_name};", source: source_script,
lang: "painless", lang: "painless",
params: { params: expected_fields
field_name => field_value
}
} }
update_by_query(objects, script) update_by_query(objects, script)
end end
def remove_field_from_objects(objects) def remove_field_from_objects(objects)
script = { source_script = expected_fields.map do |field_name, _|
source: "ctx._source.remove('#{field_name}')" "ctx._source.remove('#{field_name}');"
end.join
script = {
source: source_script
} }
update_by_query(objects, script) update_by_query(objects, script)
......
...@@ -109,7 +109,8 @@ ...@@ -109,7 +109,8 @@
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) } let_it_be(:subgroup) { create(:group, parent: group) }
let_it_be(:project) { create(:project, :internal, namespace: subgroup) } let_it_be(:project) { create(:project, :internal, namespace: subgroup) }
let_it_be(:issue) { create(:issue, project: project, assignees: [assignee]) } let_it_be(:label) { create(:label) }
let_it_be(:issue) { create(:labeled_issue, project: project, assignees: [assignee], labels: [label]) }
let_it_be(:award_emoji) { create(:award_emoji, :upvote, awardable: issue) } let_it_be(:award_emoji) { create(:award_emoji, :upvote, awardable: issue) }
it "returns json with all needed elements" do it "returns json with all needed elements" do
...@@ -127,7 +128,9 @@ ...@@ -127,7 +128,9 @@
'type' => issue.es_type, 'type' => issue.es_type,
'state' => issue.state, 'state' => issue.state,
'upvotes' => 1, 'upvotes' => 1,
'namespace_ancestry_ids' => "#{group.id}-#{subgroup.id}-" 'namespace_ancestry_ids' => "#{group.id}-#{subgroup.id}-",
'label_ids' => [label.id.to_s],
'schema_version' => 22_08
}) })
expected_hash['assignee_id'] = [assignee.id] expected_hash['assignee_id'] = [assignee.id]
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册