earth 0.5.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/TODO +2 -0
- data/bin/earth_tester.rb +62 -9
- data/earth.gemspec +7 -4
- data/lib/earth.rb +18 -17
- data/lib/earth/air.rb +2 -0
- data/lib/earth/air/aircraft.rb +76 -19
- data/lib/earth/air/aircraft/data_miner.rb +1 -63
- data/lib/earth/air/aircraft_class.rb +48 -12
- data/lib/earth/air/aircraft_class/data_miner.rb +3 -46
- data/lib/earth/air/aircraft_fuel_use_equation.rb +11 -13
- data/lib/earth/air/aircraft_instance.rb +9 -0
- data/lib/earth/air/aircraft_instance_seat_class.rb +12 -0
- data/lib/earth/air/airline.rb +6 -8
- data/lib/earth/air/airline/data_miner.rb +3 -3
- data/lib/earth/air/airport.rb +8 -10
- data/lib/earth/air/airport/data_miner.rb +1 -1
- data/lib/earth/air/bts_aircraft.rb +3 -5
- data/lib/earth/air/flight_distance_class.rb +4 -6
- data/lib/earth/air/flight_seat_class.rb +5 -7
- data/lib/earth/air/flight_segment.rb +58 -42
- data/lib/earth/air/flight_segment/data_miner.rb +11 -26
- data/lib/earth/automobile.rb +1 -0
- data/lib/earth/automobile/automobile_fuel.rb +78 -25
- data/lib/earth/automobile/automobile_fuel/data_miner.rb +5 -72
- data/lib/earth/automobile/automobile_make.rb +14 -6
- data/lib/earth/automobile/automobile_make/data_miner.rb +20 -35
- data/lib/earth/automobile/automobile_make_fleet_year.rb +39 -10
- data/lib/earth/automobile/automobile_make_fleet_year/data_miner.rb +0 -29
- data/lib/earth/automobile/automobile_make_model.rb +30 -9
- data/lib/earth/automobile/automobile_make_model/data_miner.rb +11 -26
- data/lib/earth/automobile/automobile_make_model_year.rb +41 -12
- data/lib/earth/automobile/automobile_make_model_year/data_miner.rb +14 -34
- data/lib/earth/automobile/automobile_make_model_year_variant.rb +56 -38
- data/lib/earth/automobile/automobile_make_model_year_variant/data_miner.rb +15 -61
- data/lib/earth/automobile/automobile_make_year.rb +15 -8
- data/lib/earth/automobile/automobile_make_year/data_miner.rb +17 -51
- data/lib/earth/automobile/automobile_size_class.rb +78 -14
- data/lib/earth/automobile/automobile_size_class/data_miner.rb +0 -66
- data/lib/earth/automobile/automobile_size_class_year.rb +38 -10
- data/lib/earth/automobile/automobile_size_class_year/data_miner.rb +0 -30
- data/lib/earth/automobile/automobile_type_fuel_age.rb +60 -11
- data/lib/earth/automobile/automobile_type_fuel_age/data_miner.rb +10 -65
- data/lib/earth/automobile/automobile_type_fuel_control.rb +41 -10
- data/lib/earth/automobile/automobile_type_fuel_control/data_miner.rb +0 -33
- data/lib/earth/automobile/automobile_type_fuel_year.rb +60 -15
- data/lib/earth/automobile/automobile_type_fuel_year/data_miner.rb +1 -52
- data/lib/earth/automobile/automobile_type_fuel_year_age.rb +64 -12
- data/lib/earth/automobile/automobile_type_fuel_year_age/data_miner.rb +1 -59
- data/lib/earth/automobile/automobile_type_fuel_year_control.rb +31 -10
- data/lib/earth/automobile/automobile_type_fuel_year_control/data_miner.rb +2 -32
- data/lib/earth/automobile/automobile_type_year.rb +51 -10
- data/lib/earth/automobile/automobile_type_year/data_miner.rb +1 -43
- data/lib/earth/automobile/data_miner.rb +1 -0
- data/lib/earth/bus/bus_class.rb +108 -28
- data/lib/earth/bus/bus_class/data_miner.rb +0 -88
- data/lib/earth/bus/bus_fuel.rb +83 -15
- data/lib/earth/bus/bus_fuel/data_miner.rb +0 -76
- data/lib/earth/bus/bus_fuel_control.rb +8 -10
- data/lib/earth/bus/bus_fuel_year_control.rb +7 -9
- data/lib/earth/bus/bus_fuel_year_control/data_miner.rb +1 -5
- data/lib/earth/computation/computation_carrier.rb +11 -5
- data/lib/earth/computation/computation_carrier/data_miner.rb +0 -7
- data/lib/earth/computation/computation_carrier_instance_class.rb +25 -8
- data/lib/earth/computation/computation_carrier_instance_class/data_miner.rb +0 -18
- data/lib/earth/computation/computation_carrier_region.rb +5 -7
- data/lib/earth/diet/diet_class.rb +14 -16
- data/lib/earth/diet/food_group.rb +7 -9
- data/lib/earth/fuel/fuel.rb +14 -16
- data/lib/earth/fuel/fuel/data_miner.rb +7 -3
- data/lib/earth/fuel/fuel_price.rb +4 -6
- data/lib/earth/fuel/fuel_type.rb +12 -14
- data/lib/earth/fuel/fuel_year.rb +57 -16
- data/lib/earth/fuel/fuel_year/data_miner.rb +0 -43
- data/lib/earth/fuel/greenhouse_gas.rb +46 -9
- data/lib/earth/fuel/greenhouse_gas/data_miner.rb +0 -38
- data/lib/earth/hospitality/lodging_class.rb +10 -12
- data/lib/earth/industry/industry.rb +3 -5
- data/lib/earth/industry/industry_product.rb +6 -8
- data/lib/earth/industry/industry_product_line.rb +5 -7
- data/lib/earth/industry/industry_sector.rb +5 -7
- data/lib/earth/industry/merchant.rb +4 -6
- data/lib/earth/industry/merchant_category.rb +3 -5
- data/lib/earth/industry/merchant_category_industry.rb +5 -7
- data/lib/earth/industry/product_line.rb +5 -7
- data/lib/earth/industry/product_line_industry_product.rb +5 -7
- data/lib/earth/industry/sector.rb +5 -7
- data/lib/earth/locality/census_division.rb +21 -23
- data/lib/earth/locality/census_region.rb +3 -5
- data/lib/earth/locality/climate_division.rb +5 -7
- data/lib/earth/locality/country.rb +13 -15
- data/lib/earth/locality/egrid_region.rb +14 -5
- data/lib/earth/locality/egrid_region/data_miner.rb +0 -10
- data/lib/earth/locality/egrid_subregion.rb +71 -18
- data/lib/earth/locality/egrid_subregion/data_miner.rb +0 -59
- data/lib/earth/locality/petroleum_administration_for_defense_district.rb +6 -8
- data/lib/earth/locality/state.rb +6 -8
- data/lib/earth/locality/urbanity.rb +2 -4
- data/lib/earth/locality/urbanity/data_miner.rb +7 -3
- data/lib/earth/locality/zip_code.rb +8 -10
- data/lib/earth/pet/breed.rb +5 -7
- data/lib/earth/pet/breed_gender.rb +6 -8
- data/lib/earth/pet/gender.rb +2 -4
- data/lib/earth/pet/species.rb +15 -17
- data/lib/earth/rail/rail_class.rb +64 -14
- data/lib/earth/rail/rail_class/data_miner.rb +0 -51
- data/lib/earth/residence/air_conditioner_use.rb +4 -6
- data/lib/earth/residence/air_conditioner_use/data_miner.rb +7 -3
- data/lib/earth/residence/clothes_machine_use.rb +4 -6
- data/lib/earth/residence/clothes_machine_use/data_miner.rb +11 -9
- data/lib/earth/residence/dishwasher_use.rb +4 -6
- data/lib/earth/residence/dishwasher_use/data_miner.rb +11 -9
- data/lib/earth/residence/residence_appliance.rb +4 -6
- data/lib/earth/residence/residence_class.rb +2 -4
- data/lib/earth/residence/residence_class/data_miner.rb +7 -3
- data/lib/earth/residence/residence_fuel_price.rb +12 -14
- data/lib/earth/residence/residence_fuel_price/data_miner.rb +7 -0
- data/lib/earth/residence/residence_fuel_type.rb +6 -8
- data/lib/earth/residence/residential_energy_consumption_survey_response.rb +91 -93
- data/lib/earth/residence/residential_energy_consumption_survey_response/data_miner.rb +9 -8
- data/lib/earth/shipping/carrier.rb +57 -10
- data/lib/earth/shipping/carrier/data_miner.rb +0 -48
- data/lib/earth/shipping/carrier_mode.rb +41 -10
- data/lib/earth/shipping/carrier_mode/data_miner.rb +0 -33
- data/lib/earth/shipping/shipment_mode.rb +30 -7
- data/lib/earth/shipping/shipment_mode/data_miner.rb +0 -23
- data/lib/earth/utils.rb +45 -0
- data/lib/earth/version.rb +1 -1
- data/spec/earth/air/aircraft_spec.rb +1 -1
- data/vendor/clean_find_in_batches/init.rb +35 -0
- metadata +74 -47
data/Gemfile
CHANGED
data/TODO
ADDED
data/bin/earth_tester.rb
CHANGED
@@ -14,19 +14,72 @@ end
|
|
14
14
|
require 'active_support/all'
|
15
15
|
require 'active_record'
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
case ENV['EARTH_DB_ADAPTER']
|
18
|
+
when 'mysql'
|
19
|
+
adapter = 'mysql'
|
20
|
+
database = 'test_earth'
|
21
|
+
username = 'root'
|
22
|
+
password = 'password'
|
23
|
+
|
24
|
+
# system %{mysql -u #{username} -p#{password} -e "DROP DATABASE #{database}"}
|
25
|
+
# system %{mysql -u #{username} -p#{password} -e "CREATE DATABASE #{database}"}
|
26
|
+
when 'sqlite'
|
27
|
+
adapter = 'sqlite3'
|
28
|
+
database = ':memory:'
|
29
|
+
username = nil
|
30
|
+
password = nil
|
31
|
+
else
|
32
|
+
adapter = 'postgresql'
|
33
|
+
username = ENV['EARTH_POSTGRES_USERNAME'] || `whoami`.chomp
|
34
|
+
password = ENV['EARTH_POSTGRES_PASSWORD']
|
35
|
+
database = ENV['EARTH_POSTGRES_DATABASE'] || 'test_earth'
|
36
|
+
|
37
|
+
createdb_bin = ENV['EARTH_CREATEDB_BIN'] || 'createdb'
|
38
|
+
dropdb_bin = ENV['EARTH_DROPDB_BIN'] || 'dropdb'
|
39
|
+
# system %{#{dropdb_bin} #{database}}
|
40
|
+
# system %{#{createdb_bin} #{database}}
|
41
|
+
end
|
42
|
+
|
43
|
+
config = {
|
44
|
+
'encoding' => 'utf8',
|
45
|
+
'adapter' => adapter,
|
46
|
+
'database' => database,
|
47
|
+
}
|
48
|
+
config['username'] = username if username
|
49
|
+
config['password'] = password if password
|
50
|
+
|
51
|
+
ActiveRecord::Base.establish_connection config
|
24
52
|
|
25
53
|
require 'earth'
|
26
54
|
|
27
|
-
|
55
|
+
domain = ARGV[0]
|
56
|
+
|
57
|
+
Earth.init domain, :load_data_miner => true, :apply_schemas => true
|
28
58
|
|
29
59
|
ActiveRecord::Base.logger = Logger.new $stderr
|
30
60
|
ActiveRecord::Base.logger.level = Logger::INFO
|
31
61
|
|
32
|
-
|
62
|
+
def show_resource(resource)
|
63
|
+
resource_model = resource.constantize
|
64
|
+
if (warnings = resource_model.table_warnings).any?
|
65
|
+
$stderr.puts
|
66
|
+
$stderr.puts '#'*50
|
67
|
+
$stderr.puts "# #{resource}"
|
68
|
+
$stderr.puts '#'*50
|
69
|
+
$stderr.puts
|
70
|
+
warnings.each do |warning|
|
71
|
+
$stderr.puts "* #{warning}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if (resource = ARGV[1].to_s.camelcase).present?
|
77
|
+
resource.constantize.run_data_miner!
|
78
|
+
show_resource resource
|
79
|
+
else
|
80
|
+
DataMiner.run
|
81
|
+
Earth.search(domain).each do |resource|
|
82
|
+
show_resource resource
|
83
|
+
end
|
84
|
+
end
|
85
|
+
# ARGV[1].split(/[^a-z_]/i).each { |underscore| underscore.camelcase.constantize.run_data_miner! }
|
data/earth.gemspec
CHANGED
@@ -27,23 +27,26 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.require_paths = ["lib"]
|
28
28
|
s.rubygems_version = %q{1.3.7}
|
29
29
|
|
30
|
-
s.add_runtime_dependency 'data_miner'
|
30
|
+
s.add_runtime_dependency 'data_miner', '>=1.3'
|
31
31
|
s.add_runtime_dependency 'to_regexp'
|
32
32
|
s.add_runtime_dependency 'cohort_scope'
|
33
|
+
s.add_runtime_dependency 'table_warnings', '>=0.0.6'
|
33
34
|
s.add_runtime_dependency 'remote_table', '>=1.2.3'
|
34
35
|
s.add_runtime_dependency 'falls_back_on'
|
35
36
|
s.add_runtime_dependency 'fixed_width-multibyte'
|
36
37
|
s.add_runtime_dependency 'geokit-rails'
|
37
38
|
s.add_runtime_dependency 'loose_tight_dictionary', '>=0.2.3'
|
38
|
-
s.add_runtime_dependency 'weighted_average'
|
39
|
-
s.add_runtime_dependency '
|
39
|
+
s.add_runtime_dependency 'weighted_average', '>=1'
|
40
|
+
# s.add_runtime_dependency 'mini_record' # need https://github.com/DAddYE/mini_record/pull/7 - for now install manually from https://github.com/seamusabshere/mini_record
|
41
|
+
s.add_runtime_dependency 'activesupport'
|
42
|
+
s.add_runtime_dependency 'activerecord'
|
40
43
|
s.add_development_dependency 'bundler'
|
41
44
|
s.add_development_dependency 'bueller'
|
42
45
|
s.add_development_dependency 'cucumber'
|
43
46
|
s.add_development_dependency 'rake'
|
44
47
|
s.add_development_dependency 'rdoc'
|
45
|
-
s.add_development_dependency 'rdoc'
|
46
48
|
s.add_development_dependency 'rspec'
|
47
49
|
s.add_development_dependency 'sqlite3-ruby'
|
48
50
|
s.add_development_dependency 'mysql' # for bin/earth_tester.rb
|
51
|
+
s.add_development_dependency 'pg'
|
49
52
|
end
|
data/lib/earth.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'active_support/core_ext'
|
1
2
|
require 'active_record'
|
2
3
|
require 'cohort_scope'
|
3
4
|
require 'earth/conversions_ext'
|
@@ -7,22 +8,15 @@ require 'falls_back_on'
|
|
7
8
|
require 'weighted_average'
|
8
9
|
require 'fixed_width'
|
9
10
|
require 'errata'
|
10
|
-
require '
|
11
|
+
require 'mini_record'
|
12
|
+
require 'table_warnings'
|
11
13
|
require 'loose_tight_dictionary'
|
12
14
|
require 'loose_tight_dictionary/cached_result'
|
13
15
|
|
14
|
-
# hackety hack
|
15
|
-
def INSERT_IGNORE(cmd)
|
16
|
-
if ActiveRecord::Base.connection.adapter_name.downcase == 'sqlite'
|
17
|
-
prefix = 'INSERT'
|
18
|
-
else
|
19
|
-
prefix = 'INSERT IGNORE'
|
20
|
-
end
|
21
|
-
ActiveRecord::Base.connection.execute "#{prefix} #{cmd}"
|
22
|
-
end
|
23
|
-
|
24
16
|
# The earth module is an interface for loading data models from various domains.
|
25
17
|
module Earth
|
18
|
+
autoload :Utils, 'earth/utils'
|
19
|
+
|
26
20
|
extend self
|
27
21
|
|
28
22
|
# Takes argument like Earth.search(['air'])
|
@@ -78,6 +72,7 @@ module Earth
|
|
78
72
|
options = args.last.is_a?(Hash) ? args.pop.symbolize_keys : {}
|
79
73
|
domains = args.empty? ? [ :all ] : args.map(&:to_sym)
|
80
74
|
|
75
|
+
_configure_database_connection
|
81
76
|
_load_plugins
|
82
77
|
_load_domains domains, options
|
83
78
|
_decorate_resources options
|
@@ -86,6 +81,12 @@ module Earth
|
|
86
81
|
|
87
82
|
private
|
88
83
|
|
84
|
+
def _configure_database_connection
|
85
|
+
if ActiveRecord::Base.connection.adapter_name =~ /mysql/i
|
86
|
+
ActiveRecord::Base.connection.execute("SET SQL_MODE = 'PIPES_AS_CONCAT'")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
89
90
|
# TODO sabshere don't use directories to specify domains
|
90
91
|
# * you have 20 million data_miner.rb files which are easy to confuse
|
91
92
|
# * you have to go all over the filesystem to figure things out
|
@@ -119,13 +120,13 @@ module Earth
|
|
119
120
|
resource_model.data_miner_config.steps.push pull_dependencies_step
|
120
121
|
end
|
121
122
|
|
122
|
-
def
|
123
|
+
def _prepend_auto_upgrade_step_to_data_miner(resource)
|
123
124
|
resource_model = resource.constantize
|
124
|
-
return if resource_model.data_miner_config.steps.any? { |step| step.description == :
|
125
|
+
return if resource_model.data_miner_config.steps.any? { |step| step.description == :auto_upgrade! }
|
125
126
|
|
126
|
-
|
127
|
+
auto_upgrade_step = DataMiner::Process.new resource_model.data_miner_config, :auto_upgrade!
|
127
128
|
|
128
|
-
resource_model.data_miner_config.steps.unshift
|
129
|
+
resource_model.data_miner_config.steps.unshift auto_upgrade_step
|
129
130
|
end
|
130
131
|
|
131
132
|
TAPS_STEP = 'Tap the Brighter Planet data server'
|
@@ -144,7 +145,7 @@ module Earth
|
|
144
145
|
next unless ::Object.const_defined?(resource)
|
145
146
|
_append_pull_dependencies_step_to_data_miner resource
|
146
147
|
if options[:apply_schemas] or options[:load_data_miner]
|
147
|
-
|
148
|
+
_prepend_auto_upgrade_step_to_data_miner resource
|
148
149
|
else
|
149
150
|
_prepend_taps_step_to_data_miner resource
|
150
151
|
end
|
@@ -154,7 +155,7 @@ module Earth
|
|
154
155
|
def _load_schemas(selected_resources, options)
|
155
156
|
return unless options[:apply_schemas]
|
156
157
|
selected_resources.each do |resource|
|
157
|
-
resource.constantize.
|
158
|
+
resource.constantize.auto_upgrade!
|
158
159
|
end
|
159
160
|
end
|
160
161
|
end
|
data/lib/earth/air.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'earth/air/aircraft'
|
2
2
|
require 'earth/air/aircraft_class'
|
3
3
|
require 'earth/air/aircraft_fuel_use_equation'
|
4
|
+
require 'earth/air/aircraft_instance'
|
5
|
+
require 'earth/air/aircraft_instance_seat_class'
|
4
6
|
require 'earth/air/airline'
|
5
7
|
require 'earth/air/airport'
|
6
8
|
require 'earth/air/bts_aircraft'
|
data/lib/earth/air/aircraft.rb
CHANGED
@@ -4,8 +4,24 @@ class Aircraft < ActiveRecord::Base
|
|
4
4
|
belongs_to :aircraft_class, :foreign_key => 'class_code', :primary_key => 'code'
|
5
5
|
belongs_to :fuel_use_equation, :foreign_key => 'fuel_use_code', :primary_key => 'code', :class_name => 'AircraftFuelUseEquation'
|
6
6
|
|
7
|
-
|
7
|
+
col :icao_code
|
8
|
+
col :manufacturer_name
|
9
|
+
col :model_name
|
10
|
+
col :description
|
11
|
+
col :aircraft_type
|
12
|
+
col :engine_type
|
13
|
+
col :engines, :type => :integer
|
14
|
+
col :weight_class
|
15
|
+
col :class_code
|
16
|
+
col :fuel_use_code
|
17
|
+
col :seats, :type => :float
|
18
|
+
col :passengers, :type => :float
|
19
|
+
|
20
|
+
# Enable aircraft.flight_segments
|
21
|
+
cache_loose_tight_dictionary_matches_with :flight_segments, :primary_key => :description, :foreign_key => :aircraft_description
|
22
|
+
|
8
23
|
class << self
|
24
|
+
# set up a loose_tight_dictionary for matching Aircraft description with FlightSegment aircraft_description
|
9
25
|
def loose_tight_dictionary
|
10
26
|
@loose_tight_dictionary ||= LooseTightDictionary.new(Aircraft.all,
|
11
27
|
:haystack_reader => lambda { |record| record.description },
|
@@ -15,23 +31,64 @@ class Aircraft < ActiveRecord::Base
|
|
15
31
|
:must_match_blocking => true,
|
16
32
|
:first_blocking_decides => true)
|
17
33
|
end
|
18
|
-
end
|
19
34
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
string 'fuel_use_code'
|
31
|
-
float 'seats'
|
32
|
-
float 'passengers'
|
33
|
-
end
|
35
|
+
# FIXME TODO do we want to restrict this to certain years?
|
36
|
+
# Derive some average characteristics from flight segments
|
37
|
+
def update_averages!
|
38
|
+
manually_cache_flight_segments!
|
39
|
+
find_each do |aircraft|
|
40
|
+
aircraft.seats = aircraft.flight_segments.weighted_average :seats_per_flight, :weighted_by => :passengers
|
41
|
+
aircraft.passengers = aircraft.flight_segments.sum :passengers
|
42
|
+
aircraft.save!
|
43
|
+
end
|
44
|
+
end
|
34
45
|
|
35
|
-
|
36
|
-
|
37
|
-
|
46
|
+
# Cache fuzzy matches between FlightSegment aircraft_description and Aircraft description
|
47
|
+
def manually_cache_flight_segments!
|
48
|
+
FlightSegment.run_data_miner!
|
49
|
+
LooseTightDictionary::CachedResult.setup
|
50
|
+
connection.select_values("SELECT DISTINCT(aircraft_description) FROM flight_segments WHERE aircraft_description IS NOT NULL").each do |original_description|
|
51
|
+
# If the flight segment's aircraft_description contains '/' then it describes multiple aircraft.
|
52
|
+
# We need to synthesize descriptions for those aircraft, find all Aircraft that fuzzily match the
|
53
|
+
# synthesized descriptions, and associate those Aircraft with the original aircraft_description.
|
54
|
+
# e.g. boeing 747-100/200
|
55
|
+
if original_description.include?('/')
|
56
|
+
# Pull out the complete first aircraft description
|
57
|
+
# e.g. 'boeing 747-100'
|
58
|
+
first_description = original_description.split('/')[0]
|
59
|
+
|
60
|
+
# Pull out the root of the description - the text up to and including the last ' ' or '-'
|
61
|
+
# e.g. 'boeing 747-'
|
62
|
+
root_length = first_description.rindex(/[ \-]/)
|
63
|
+
root = first_description.slice(0..root_length)
|
64
|
+
|
65
|
+
# Pull out the suffixes - the text separated by forward slashes
|
66
|
+
# e.g. ['100', '200']
|
67
|
+
suffixes = original_description.split(root)[1].split('/')
|
68
|
+
|
69
|
+
# Create an array of synthesized descriptions by appending each suffix to the root
|
70
|
+
# e.g. ['boeing 747-100', 'boeing 747-200']
|
71
|
+
suffixes.map{ |suffix| root + suffix }.each do |synthesized_description|
|
72
|
+
# Look up the Aircraft that match each synthesized description and associate
|
73
|
+
# them with the original flight segment aircraft_description
|
74
|
+
Aircraft.loose_tight_dictionary.find_all(synthesized_description).each do |aircraft|
|
75
|
+
attrs = {
|
76
|
+
:a_class => "Aircraft",
|
77
|
+
:a => aircraft.description,
|
78
|
+
:b_class => "FlightSegment",
|
79
|
+
:b => original_description
|
80
|
+
}
|
81
|
+
unless ::LooseTightDictionary::CachedResult.exists? attrs
|
82
|
+
::LooseTightDictionary::CachedResult.create! attrs
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
# If the flight segment's aircraft_description doesn't contain '/' we can use
|
87
|
+
# a method provided by loose_tight_dictionary to associate it with Aircraft
|
88
|
+
else
|
89
|
+
FlightSegment.find_by_aircraft_description(original_description).cache_aircraft!
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -21,68 +21,6 @@ Aircraft.class_eval do
|
|
21
21
|
@manufacturer_whitelist.any? { |manufacturer_regexp| manufacturer_regexp.match candidate }
|
22
22
|
end
|
23
23
|
|
24
|
-
# FIXME TODO do we want to restrict this to certain years?
|
25
|
-
# Derive some average characteristics from flight segments
|
26
|
-
def self.update_averages!
|
27
|
-
FlightSegment.run_data_miner!
|
28
|
-
manually_cache_flight_segments!
|
29
|
-
find_each do |aircraft|
|
30
|
-
aircraft.seats = aircraft.flight_segments.weighted_average :seats_per_flight, :weighted_by => :passengers
|
31
|
-
aircraft.passengers = aircraft.flight_segments.sum :passengers
|
32
|
-
aircraft.save
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Cache fuzzy matches between FlightSegment aircraft_description and Aircraft description
|
37
|
-
def self.manually_cache_flight_segments!
|
38
|
-
FlightSegment.run_data_miner!
|
39
|
-
LooseTightDictionary::CachedResult.setup
|
40
|
-
FlightSegment.find_by_sql("SELECT * FROM flight_segments GROUP BY aircraft_description HAVING aircraft_description IS NOT NULL").each do |flight_segment|
|
41
|
-
original_description = flight_segment.aircraft_description
|
42
|
-
|
43
|
-
# If the flight segment's aircraft_description contains '/' then it describes multiple aircraft.
|
44
|
-
# We need to synthesize descriptions for those aircraft, find all Aircraft that fuzzily match the
|
45
|
-
# synthesized descriptions, and associate those Aircraft with the original aircraft_description.
|
46
|
-
# e.g. boeing 747-100/200
|
47
|
-
if original_description.include?("/")
|
48
|
-
# Pull out the complete first aircraft description
|
49
|
-
# e.g. 'boeing 747-100'
|
50
|
-
first_description = original_description.split('/')[0]
|
51
|
-
|
52
|
-
# Pull out the root of the description - the text up to and including the last ' ' or '-'
|
53
|
-
# e.g. 'boeing 747-'
|
54
|
-
root_length = first_description.rindex(/[ \-]/)
|
55
|
-
root = first_description.slice(0..root_length)
|
56
|
-
|
57
|
-
# Pull out the suffixes - the text separated by forward slashes
|
58
|
-
# e.g. ['100', '200']
|
59
|
-
suffixes = original_description.split(root)[1].split('/')
|
60
|
-
|
61
|
-
# Create an array of synthesized descriptions by appending each suffix to the root
|
62
|
-
# e.g. ['boeing 747-100', 'boeing 747-200']
|
63
|
-
suffixes.map{ |suffix| root + suffix }.each do |synthesized_description|
|
64
|
-
# Look up the Aircraft that match each synthesized description and associate
|
65
|
-
# them with the original flight segment aircraft_description
|
66
|
-
Aircraft.loose_tight_dictionary.find_all(synthesized_description).each do |aircraft|
|
67
|
-
attrs = {
|
68
|
-
:a_class => "Aircraft",
|
69
|
-
:a => aircraft.description,
|
70
|
-
:b_class => "FlightSegment",
|
71
|
-
:b => original_description
|
72
|
-
}
|
73
|
-
unless ::LooseTightDictionary::CachedResult.exists? attrs
|
74
|
-
::LooseTightDictionary::CachedResult.create! attrs
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
# If the flight segment's aircraft_description doesn't contain '/' we can use
|
79
|
-
# a method provided by loose_tight_dictionary to associate it with Aircraft
|
80
|
-
else
|
81
|
-
flight_segment.cache_aircraft!
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
24
|
data_miner do
|
87
25
|
('A'..'Z').each do |letter|
|
88
26
|
import("aircraft made by whitelisted manufacturers whose ICAO code starts with '#{letter}' from the FAA",
|
@@ -140,7 +78,7 @@ Aircraft.class_eval do
|
|
140
78
|
end
|
141
79
|
|
142
80
|
process :update_averages!
|
143
|
-
|
81
|
+
|
144
82
|
# FIXME TODO verify this
|
145
83
|
end
|
146
84
|
end
|
@@ -2,6 +2,17 @@ class AircraftClass < ActiveRecord::Base
|
|
2
2
|
set_primary_key :code
|
3
3
|
|
4
4
|
has_many :aircraft, :foreign_key => 'class_code', :primary_key => 'code'
|
5
|
+
|
6
|
+
col :code
|
7
|
+
col :m3, :type => :float
|
8
|
+
col :m3_units
|
9
|
+
col :m2, :type => :float
|
10
|
+
col :m2_units
|
11
|
+
col :m1, :type => :float
|
12
|
+
col :m1_units
|
13
|
+
col :b, :type => :float
|
14
|
+
col :b_units
|
15
|
+
col :seats, :type => :float
|
5
16
|
|
6
17
|
def fuel_use_coefficients
|
7
18
|
[m3, m2, m1, b]
|
@@ -10,17 +21,42 @@ class AircraftClass < ActiveRecord::Base
|
|
10
21
|
def valid_fuel_use_equation?
|
11
22
|
fuel_use_coefficients.all?(&:present?) and fuel_use_coefficients.any?(&:nonzero?)
|
12
23
|
end
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def update_averages!
|
27
|
+
Aircraft.run_data_miner!
|
28
|
+
AircraftFuelUseEquation.run_data_miner!
|
29
|
+
find_each do |aircraft_class|
|
30
|
+
cumulative_passengers = 0
|
31
|
+
aircraft_class.m3 = 0
|
32
|
+
aircraft_class.m2 = 0
|
33
|
+
aircraft_class.m1 = 0
|
34
|
+
aircraft_class.b = 0
|
35
|
+
|
36
|
+
aircraft_class.aircraft.where('passengers > 0 AND fuel_use_code IS NOT NULL').each do |a|
|
37
|
+
cumulative_passengers += a.passengers
|
38
|
+
aircraft_class.m3 += a.fuel_use_equation.m3 * a.passengers
|
39
|
+
aircraft_class.m2 += a.fuel_use_equation.m2 * a.passengers
|
40
|
+
aircraft_class.m1 += a.fuel_use_equation.m1 * a.passengers
|
41
|
+
aircraft_class.b += a.fuel_use_equation.b * a.passengers
|
42
|
+
end
|
43
|
+
|
44
|
+
if cumulative_passengers > 0
|
45
|
+
aircraft_class.m3 /= cumulative_passengers
|
46
|
+
aircraft_class.m2 /= cumulative_passengers
|
47
|
+
aircraft_class.m1 /= cumulative_passengers
|
48
|
+
aircraft_class.b /= cumulative_passengers
|
49
|
+
end
|
50
|
+
|
51
|
+
aircraft_class.seats = aircraft_class.aircraft.weighted_average(:seats, :weighted_by => :passengers)
|
52
|
+
|
53
|
+
aircraft_class.m3_units = 'kilograms_per_cubic_nautical_mile'
|
54
|
+
aircraft_class.m2_units = 'kilograms_per_square_nautical_mile'
|
55
|
+
aircraft_class.m1_units = 'kilograms_per_nautical_mile'
|
56
|
+
aircraft_class.b_units = 'kilograms'
|
57
|
+
|
58
|
+
aircraft_class.save!
|
59
|
+
end
|
60
|
+
end
|
25
61
|
end
|
26
62
|
end
|