module Abstractor::Abstractable::InstanceMethods
Public Instance Methods
The method for generating abstractions from the abstractable entity.
The generation of abstactions is based on the setup of Abstactor::AbstractorAbstactionSchema, Abstractor::AbstractorSubject
, Abstractor::AbstractorSubjectGroup
and Abstractor::AbstractorAbstractionSource
associated to the abstractable entity.
Namespacing allows for different sets data points to be associated to the same abstractable entity.
Namespacing is achieved by setting the Abstractor::AbstractorSubject#namespace_type and Abstractor::AbstractorSubject#namespace_id attributes.
Passing a namespace to this method will restrict the generation of abstractions to the given namespace. Otherwise, all configured abstractions associated to the abstractable entity will be generated.
A practical example of the use of a namespace would be two different clincal departments wanting to chart abstract two distinct sets of datapoints for progress notes extracted from an electronic medical record system. @param [Hash] options the options to filter the generation of abstractions to a namespace. @option options [String] :namespace_type The type parameter of the namespace. @option options [Integer] :namespace_id The instance parameter of the namespace. @option options [List of integers] :abstractor_abstraction_schema_ids List of abstractor_abstraction_schema_ids to limit abstraction. @return [void]
# File lib/abstractor/abstractable.rb, line 89 def abstract(options = {}) options = { namespace_type: nil, namespace_id: nil, abstractor_abstraction_schema_ids: [] }.merge(options) sentinental_groups = [] self.class.abstractor_subjects(options).each do |abstractor_subject| abstractor_subject.abstract(self) sentinental_groups << abstractor_subject.abstractor_subject_group if abstractor_subject.abstractor_subject_group && abstractor_subject.abstractor_subject_group.has_subtype?(Abstractor::Enum::ABSTRACTOR_GROUP_SENTINENTAL_SUBTYPE) end sentinental_groups.uniq.map{|sentinental_group| regroup_sentinental_suggestions(sentinental_group, options)} end
Returns all abstraction groups for the abstractable entity by a namespace.
@param [Hash] options the options to filter the list of abstraction groups to a namespace. @option options [String] :namespace_type The type parameter of the namespace. @option options [Integer] :namespace_id The instance parameter of the namespace. @return [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstractionGroup].
# File lib/abstractor/abstractable.rb, line 57 def abstractor_abstraction_groups_by_namespace(options = {}) options = { namespace_type: nil, namespace_id: nil }.merge(options) if options[:namespace_type] || options[:namespace_id] groups = abstractor_abstraction_groups.find(abstractor_abstractions_by_namespace(options).joins(:abstractor_abstraction_group).includes(:abstractor_abstraction_group).map{|s| s.abstractor_abstraction_group.id}) else groups = abstractor_abstraction_groups.not_deleted end if options[:abstractor_subject_group_id] groups.select{|g| g.abstractor_subject_group_id == options[:abstractor_subject_group_id]} else groups end end
Returns all abstractions for the abstractable entity by abstraction options.
@param [Hash] options the options to filter the list of abstractions to a namespace. @option options [Array] :abstractor_abstraction_schema_ids List of [Abstractor::AbstractorAbstractionSchema] ids @option options [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstraction]. @return [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstraction].
# File lib/abstractor/abstractable.rb, line 41 def abstractor_abstractions_by_abstraction_schemas(options = {}) options = { abstractor_abstraction_schema_ids: [], abstractor_abstractions: abstractor_abstractions.not_deleted }.merge(options) if options[:abstractor_abstraction_schema_ids].any? options[:abstractor_abstractions].joins(:abstractor_subject).where(abstractor_subjects: { abstractor_abstraction_schema_id: options[:abstractor_abstraction_schema_ids]}) else options[:abstractor_abstractions] end end
Returns all abstraction for the abstractable entity by abstractor_abstraction_status:
-
‘needs_review’: Filter abstractions without a determined value (value, unknown or not_applicable).
-
‘reviewed’: Filter abstractions having a determined value (value, unknown or not_applicable).
@param [String] abstractor_abstraction_status Filter abstractions that need review or are reviews. @param [Hash] options the options to filter abstractions to a namespace. @option options [String] :namespace_type the type parameter of the namespace. @option options [Integer] :namespace_id the instance parameter of the namespace. @return [ActiveRecord::Relation] list of [Abstractor::AbstractorAbstraction].
# File lib/abstractor/abstractable.rb, line 162 def abstractor_abstractions_by_abstractor_abstraction_status(abstractor_abstraction_status, options = {}) options = { namespace_type: nil, namespace_id: nil }.merge(options) case abstractor_abstraction_status when Abstractor::Enum::ABSTRACTION_STATUS_NEEDS_REVIEW abstractor_abstractions_by_namespace(options).select { |abstractor_abstraction| abstractor_abstraction.value.blank? && abstractor_abstraction.unknown.blank? && abstractor_abstraction.not_applicable.blank? } when Abstractor::Enum::ABSTRACTION_STATUS_REVIEWED abstractor_abstractions_by_namespace(options).select { |abstractor_abstraction| !abstractor_abstraction.value.blank? || !abstractor_abstraction.unknown.blank? || !abstractor_abstraction.not_applicable.blank? } end end
Returns all abstractions for the abstractable entity by a namespace.
@param [Hash] options the options to filter the list of abstractions to a namespace. @option options [String] :namespace_type The type parameter of the namespace. @option options [Integer] :namespace_id The instance parameter of the namespace. @return [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstraction].
# File lib/abstractor/abstractable.rb, line 25 def abstractor_abstractions_by_namespace(options = {}) options = { namespace_type: nil, namespace_id: nil }.merge(options) abstractions = abstractor_abstractions.not_deleted if options[:namespace_type] || options[:namespace_id] abstractions = abstractions.where(abstractor_subject_id: self.class.abstractor_subjects(options).map(&:id)) end abstractions end
Determines if provided abstractor_subject_group reached number of abstractor_abstraction_groups defined by abstractor_subject_group cardinality
@param [Integer] abstractor_subject_group_id the id of abstractor_subject_group of interest. @option options [String] :namespace_type the type parameter of the namespace. @option options [Integer] :namespace_id the instance parameter of the namespace. @return [boolean]
# File lib/abstractor/abstractable.rb, line 140 def abstractor_subject_group_complete?(abstractor_subject_group_id, options = {}) abstractor_subject_group = Abstractor::AbstractorSubjectGroup.find(abstractor_subject_group_id) if abstractor_subject_group.cardinality.blank? false else options = { namespace_type: nil, namespace_id: nil, abstractor_subject_group_id: abstractor_subject_group_id }.merge(options) abstractor_abstraction_groups = abstractor_abstraction_groups_by_namespace(options) abstractor_abstraction_groups.length == abstractor_subject_group.cardinality end end
# File lib/abstractor/abstractable.rb, line 99 def detect_abstractor_abstraction(abstractor_subject) abstractor_abstractions(true).not_deleted.detect { |abstractor_abstraction| abstractor_abstraction.abstractor_subject_id == abstractor_subject.id } end
# File lib/abstractor/abstractable.rb, line 118 def detect_abstractor_abstraction_group(abstractor_subject_group, options) abstractor_abstraction_groups(true). select { |abstractor_abstraction_group| abstractor_abstraction_group.abstractor_subject_group_id == abstractor_subject_group.id }. select { |abstractor_abstraction_group| abstractor_abstraction_group.abstractor_abstractions.joins(:abstractor_subject).where(abstractor_subjects: { namespace_type: options[:namespace_type], namespace_id: options[:namespace_id]}).any?}. first end
# File lib/abstractor/abstractable.rb, line 103 def find_or_create_abstractor_abstraction(abstractor_abstraction_schema, abstractor_subject) options = { namespace_type: abstractor_subject.namespace_type, namespace_id: abstractor_subject.namespace_id } if abstractor_abstraction = detect_abstractor_abstraction(abstractor_subject) else abstractor_abstraction = Abstractor::AbstractorAbstraction.create!(abstractor_subject: abstractor_subject, about: self) if abstractor_subject.groupable? abstractor_abstraction_group = find_or_initialize_abstractor_abstraction_group(abstractor_subject.abstractor_subject_group, options) abstractor_abstraction_group.abstractor_abstractions << abstractor_abstraction abstractor_abstraction_group.save! end end abstractor_abstraction end
# File lib/abstractor/abstractable.rb, line 125 def find_or_initialize_abstractor_abstraction_group(abstractor_subject_group, options) if abstractor_abstraction_group = detect_abstractor_abstraction_group(abstractor_subject_group, options) else abstractor_abstraction_group = Abstractor::AbstractorAbstractionGroup.new(abstractor_subject_group: abstractor_subject_group, about: self, system_generated: true) end abstractor_abstraction_group end
Regroups suggestions for subjects grouped marked with ‘sentinental’ subtype. Does not affect abstraction groups with curated values. Creates an abstraction group for each combination of suggestions that came from the same sentence. Creates groups only if there are enough abstractions.
@param [ActiveRecord::Relation] sentinental_group sentinental group to process @return [void]
# File lib/abstractor/abstractable.rb, line 223 def regroup_sentinental_suggestions(sentinental_group, options) sentinental_group_abstractor_subjects = sentinental_group.abstractor_subjects.not_deleted if options[:namespace_type] || options[:namespace_id] sentinental_group_abstractor_subjects = sentinental_group_abstractor_subjects.where(namespace_type: options[:namespace_type], namespace_id: options[:namespace_id]) end sentinental_group_abstractor_abstraction_groups = Abstractor::AbstractorAbstractionGroup.not_deleted.joins(:abstractor_subject_group, :abstractor_abstractions).where(abstractor_subject_group_id: sentinental_group.id, abstractor_abstractions: {about_id: self.id, abstractor_subject_id: sentinental_group_abstractor_subjects.map(&:id)}).distinct sentinental_group_abstractor_suggestion_sources = Abstractor::AbstractorSuggestionSource.joins(abstractor_suggestion: { abstractor_abstraction: :abstractor_abstraction_group}) .where(abstractor_abstraction_groups: { id: sentinental_group_abstractor_abstraction_groups.map(&:id)}, abstractor_abstractions: { abstractor_subject_id: sentinental_group_abstractor_subjects.map(&:id), about_id: self.id}) sentinental_abstractor_abstraction_groups = sentinental_group_abstractor_abstraction_groups.where(subtype: Abstractor::Enum::ABSTRACTOR_GROUP_SENTINENTAL_SUBTYPE) sentinental_group_abstractor_abstraction_groups.each do |abstractor_abstraction_group| unless abstractor_abstraction_group.abstractor_abstractions.not_deleted.where(about_id: self.id).where('value is not null').any? # skip abstraction groups with curated abstractions # get all suggestion sources abstractor_suggestion_sources = sentinental_group_abstractor_suggestion_sources.where(abstractor_abstraction_groups: { id: abstractor_abstraction_group.id}) # get all matched sentences sentence_match_values = abstractor_suggestion_sources.select(:sentence_match_value).distinct.map(&:sentence_match_value).compact # skip groups where all abstractions come from the same sentence unless sentence_match_values.length == 1 # create abstraction group for each sentence sentence_match_values.each do |sentence_match_value| # get all suggestion sources that reference the sentence abstractor_suggestion_sources_by_sentence = abstractor_suggestion_sources.where(sentence_match_value: sentence_match_value) abstractor_subjects = abstractor_suggestion_sources_by_sentence. map{|abstractor_suggestion_source| abstractor_suggestion_source.abstractor_suggestion.abstractor_abstraction.abstractor_subject }. reject{|abstractor_subject| abstractor_subject.abstractor_subject_group.blank? || abstractor_subject.abstractor_subject_group.id != sentinental_group.id}.uniq if abstractor_subjects.length == sentinental_group_abstractor_subjects.length matching_abstractor_suggestion_sources = sentinental_group_abstractor_suggestion_sources.where(sentence_match_value: sentence_match_value) existing_abstractor_abstraction_group = matching_abstractor_suggestion_sources. map{|abstractor_suggestion_source| abstractor_suggestion_source.abstractor_suggestion.abstractor_abstraction.abstractor_abstraction_group}. select{|aag| sentinental_abstractor_abstraction_groups.map(&:id).include? aag.id}. reject{|aag| aag.id == abstractor_abstraction_group.id}.uniq.first if existing_abstractor_abstraction_group new_abstractor_abstraction_group = existing_abstractor_abstraction_group else new_abstractor_abstraction_group = Abstractor::AbstractorAbstractionGroup.new(abstractor_subject_group: abstractor_abstraction_group.abstractor_subject_group, about: self, system_generated: true, subtype: abstractor_abstraction_group.abstractor_subject_group.subtype) end abstractor_suggestion_sources_by_sentence.all.each do |abstractor_suggestion_source| abstractor_suggestion = abstractor_suggestion_source.abstractor_suggestion abstractor_abstraction = abstractor_suggestion.abstractor_abstraction # if corresponding abstraction has more than one suggestion and should not be moved # create a new abstraction if the new group does not yet have abstraction for the same subject abstractor_subject = abstractor_abstraction.abstractor_subject existing_new_abstractor_abstraction = new_abstractor_abstraction_group.abstractor_abstractions.select{|aa| aa.abstractor_subject_id == abstractor_subject.id}.first if existing_new_abstractor_abstraction new_abstractor_abstraction = existing_new_abstractor_abstraction else if abstractor_abstraction.abstractor_suggestions.length > 1 new_abstractor_abstraction = Abstractor::AbstractorAbstraction.create!(abstractor_subject: abstractor_suggestion.abstractor_abstraction.abstractor_subject, about: self) else new_abstractor_abstraction = abstractor_abstraction new_abstractor_abstraction.abstractor_abstraction_group_member = nil new_abstractor_abstraction.build_abstractor_abstraction_group_member(abstractor_abstraction_group: new_abstractor_abstraction_group) end unless new_abstractor_abstraction_group.abstractor_abstractions.include? new_abstractor_abstraction new_abstractor_abstraction_group.abstractor_abstractions << new_abstractor_abstraction end end # if new abstraction already has matching suggestion, use it to map sources new_abstractor_suggestion = new_abstractor_abstraction.detect_abstractor_suggestion(abstractor_suggestion.suggested_value, abstractor_suggestion.unknown, abstractor_suggestion.not_applicable) # if matching suggestion does not exist, create a new suggestion if corresponding suggestion has multiple sources # and should not be moved of move existing one to the new abstraction # and map suggestion source to the new suggestion if new_abstractor_suggestion.blank? if abstractor_suggestion.abstractor_suggestion_sources.length > 1 new_abstractor_suggestion ||= Abstractor::AbstractorSuggestion.create!( abstractor_abstraction: new_abstractor_abstraction, abstractor_suggestion_status: Abstractor::AbstractorSuggestionStatus.where(name: 'Needs review').first, suggested_value: abstractor_suggestion.suggested_value, unknown: abstractor_suggestion.unknown, not_applicable: abstractor_suggestion.not_applicable ) else new_abstractor_suggestion = abstractor_suggestion end end new_abstractor_suggestion.abstractor_abstraction = new_abstractor_abstraction new_abstractor_suggestion.save! existing_abstractor_suggestion_source = abstractor_suggestion.detect_abstractor_suggestion_source(abstractor_suggestion_source.abstractor_abstraction_source, abstractor_suggestion_source.sentence_match_value, abstractor_suggestion_source.source_id, abstractor_suggestion_source.source_type, abstractor_suggestion_source.source_method, abstractor_suggestion_source.section_name) if existing_abstractor_suggestion_source && existing_abstractor_suggestion_source != abstractor_suggestion_source abstractor_suggestion_source.delete else abstractor_suggestion_source.abstractor_suggestion = new_abstractor_suggestion abstractor_suggestion_source.save! end end # do not save group if it does not have abstractions new_abstractor_abstraction_group.save! if new_abstractor_abstraction_group.abstractor_abstractions.any? end end abstractor_abstraction_group_siblings = AbstractorAbstractionGroup.not_deleted.joins(:abstractor_subject_group, :abstractor_abstractions).where(abstractor_subject_group_id: sentinental_group.id, abstractor_abstractions: {about_id: self.id, abstractor_subject_id: sentinental_group_abstractor_subjects.map(&:id)}).distinct if abstractor_abstraction_group_siblings.length > 1 abstractor_abstraction_group.reload.abstractor_abstractions.each do |abstractor_abstraction| abstractor_abstraction.abstractor_suggestions.each do |abstractor_suggestion| abstractor_suggestion.abstractor_suggestion_sources.delete_all abstractor_suggestion.abstractor_suggestion_object_value.delete if abstractor_suggestion.abstractor_suggestion_object_value abstractor_suggestion.delete end abstractor_abstraction.abstractor_indirect_sources.each do |abstractor_indirect_source| abstractor_indirect_source.delete end abstractor_abstraction.delete end abstractor_abstraction_group.reload.abstractor_abstraction_group_members.map{|a| a.delete} abstractor_abstraction_group.delete end end end end end
Removes all abstractions, suggestions and indirect sources for the abstractable entity. Optionally filtred to only ‘unreviewed’ abstractions and to a given namespace.
@param [Hash] options the options to filter the removal of abstractions. @option options [Booelan] :only_unreviewed Instructs whether to confine removal to only ‘unreviewed’ abstractions. @option options [String] :namespace_type The type parameter of the namespace to remove. @option options [Integer] :namespace_id The instance parameter of the namespace to remove. @option options [List of integers] :abstractor_abstraction_schema_ids List of abstractor_abstraction_schema_ids to limit abstraction removal. @return [void]
# File lib/abstractor/abstractable.rb, line 181 def remove_abstractions(options = {}) options = { only_unreviewed: true, namespace_type: nil, namespace_id: nil, abstractor_abstraction_schema_ids: [] }.merge(options) abstractor_abstractions = abstractor_abstractions_by_namespace(options) if options[:abstractor_abstraction_schema_ids].any? options = { abstractor_abstractions: abstractor_abstractions }.merge(options) abstractor_abstractions = abstractor_abstractions_by_abstraction_schemas(options) end abstractor_abstraction_groups = [] abstractor_abstractions.each do |abstractor_abstraction| if abstractor_abstraction.abstractor_abstraction_group abstractor_abstraction_groups << abstractor_abstraction.abstractor_abstraction_group end end abstractor_abstraction_groups.uniq! abstractor_abstractions.each do |abstractor_abstraction| if !options[:only_unreviewed] || (options[:only_unreviewed] && abstractor_abstraction.unreviewed?) abstractor_abstraction.abstractor_suggestions.each do |abstractor_suggestion| abstractor_suggestion.abstractor_suggestion_sources.destroy_all abstractor_suggestion.abstractor_suggestion_object_value.destroy if abstractor_suggestion.abstractor_suggestion_object_value abstractor_suggestion.destroy end abstractor_abstraction.abstractor_indirect_sources.each do |abstractor_indirect_source| abstractor_indirect_source.destroy end abstractor_abstraction.destroy end end abstractor_abstraction_groups.each do |abstractor_abstraction_group| if abstractor_abstraction_group.reload.abstractor_abstraction_group_members.empty? abstractor_abstraction_group.destroy end end end