nexosis_api 1.2.4 → 1.3.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
  SHA1:
3
- metadata.gz: 98843ea8efaca93ca14c66a6f8babdc8769992d7
4
- data.tar.gz: 426cdb0bcc87d9abeb21a6a4c9526e88d075e78e
3
+ metadata.gz: 05cf5a6d76290c17f23d0db1e00a5d9215dfc56c
4
+ data.tar.gz: e28cbae30ef33132f250eb200efe6545eb46091b
5
5
  SHA512:
6
- metadata.gz: 3eabe9f10de72d8634aab044c866d9a878809c04fdb3f3f428b84bb8b5a1c2e394ca12a25288a3481fe62e20e110a2a3f37cf16d8e0dd76f3babf857423d99f5
7
- data.tar.gz: 81e486c7cf604819e2350041f9cf19408beab4248e646821c3f46ff5913d5f299be57f5bcc5fba9209794ebdaeac5882e656007803523d620e62ddfe2bc6719e
6
+ metadata.gz: b17a834985acaa28a81bf3ecb2e7874b03adfd40907b9df3698b324b334bd8e0c1d51fb103cf8c521d7523d23b32c2c014392a3e0ae27689f55b48ec9a4b90ef
7
+ data.tar.gz: 06de1a773837de420b6a41cb24c32b41a50e007cdfd1eaccd2916fd18d7102448c7ea4b041545d29e1dbbefc98e759d68f9499f072fe15894b3709ad43e40e55
@@ -7,6 +7,10 @@ module NexosisApi
7
7
  end
8
8
  end
9
9
 
10
+ # A unique identififer for the algorithm
11
+ # @return [String]
12
+ attr_accessor :key
13
+
10
14
  # A friendly name for the algorithm
11
15
  # @return [String]
12
16
  attr_accessor :name
@@ -16,6 +16,8 @@ require 'nexosis_api/imports_response'
16
16
  require 'nexosis_api/join'
17
17
  require 'nexosis_api/link'
18
18
  require 'nexosis_api/metric'
19
+ require 'nexosis_api/model_summary'
20
+ require 'nexosis_api/predict_response'
19
21
  require 'nexosis_api/session_response'
20
22
  require 'nexosis_api/session_result'
21
23
  require 'nexosis_api/session'
@@ -26,6 +28,7 @@ require 'nexosis_api/client/sessions'
26
28
  require 'nexosis_api/client/datasets'
27
29
  require 'nexosis_api/client/imports'
28
30
  require 'nexosis_api/client/views'
31
+ require 'nexosis_api/client/models'
29
32
 
30
33
  module NexosisApi
31
34
  # Primary entry point to working with Nexosis API
@@ -36,13 +39,15 @@ module NexosisApi
36
39
  include Client::Datasets
37
40
  include Client::Imports
38
41
  include Client::Views
42
+ include Client::Models
39
43
 
40
44
  def initialize(options = {})
41
45
  raise ArgumentError, 'api_key was not defined' unless options[:api_key].nil? == false
42
46
  @api_key = options[:api_key]
43
47
  self.class.base_uri options[:base_uri] unless options[:base_uri].nil?
44
- @headers = {'api-key' => @api_key, 'Content-Type' => 'application/json'}
45
- @options = {headers: @headers, format: :json}
48
+ @headers = { 'api-key' => @api_key, 'Content-Type' => 'application/json',
49
+ 'User-Agent' => 'Nexosis-Ruby-API-Client/1.2' }
50
+ @options = { headers: @headers, format: :json }
46
51
  end
47
52
 
48
53
  # Gets the current account balance.
@@ -34,11 +34,9 @@ module NexosisApi
34
34
  list_dataset_url = "/data?partialName=#{partial_name}"
35
35
  response = self.class.get(list_dataset_url, headers: @headers)
36
36
  if response.success?
37
- results = []
38
- response.parsed_response['items'].each do |dr|
39
- results << NexosisApi::DatasetSummary.new(dr)
37
+ response.parsed_response['items'].map do |dr|
38
+ NexosisApi::DatasetSummary.new(dr)
40
39
  end
41
- results
42
40
  else
43
41
  raise HttpException.new("There was a problem listing datasets: #{response.code}.", "listing datasets with partial name #{partial_name}", response)
44
42
  end
@@ -55,11 +53,8 @@ module NexosisApi
55
53
  # The dates can be used independently and are inclusive. Lack of options returns all values within the given page.
56
54
  def get_dataset(dataset_name, page_number = 0, page_size = 50, query_options = {})
57
55
  response = get_dataset_internal(dataset_name, page_number, page_size, query_options)
58
- if response.success?
59
- NexosisApi::DatasetData.new(response.parsed_response)
60
- else
61
- raise HttpException.new("There was a problem getting the dataset: #{response.code}.", "getting dataset #{dataset_name}", response)
62
- end
56
+ return NexosisApi::DatasetData.new(response.parsed_response) if response.success?
57
+ raise HttpException.new("There was a problem getting the dataset: #{response.code}.", "getting dataset #{dataset_name}", response)
63
58
  end
64
59
 
65
60
  # Get the data in the set, written to a CSV file, optionally filtering it.
@@ -75,11 +70,8 @@ module NexosisApi
75
70
  # NexosisApi.client.get_dataset_csv('MyDataset', 1, 20, {:include => 'sales'})
76
71
  def get_dataset_csv(dataset_name, page_number = 0, page_size = 50, query_options = {})
77
72
  response = get_dataset_internal(dataset_name, page_number, page_size, query_options, 'text/csv')
78
- if response.success?
79
- response.body
80
- else
81
- raise HttpException.new("There was a problem getting the dataset: #{response.code}.", "getting dataset #{dataset_name}", response)
82
- end
73
+ return response.body if response.success?
74
+ raise HttpException.new("There was a problem getting the dataset: #{response.code}.", "getting dataset #{dataset_name}", response)
83
75
  end
84
76
 
85
77
  # Remove data from a data set or the entire set.
@@ -92,6 +84,7 @@ module NexosisApi
92
84
  # - cascade_forecast - will cascade deletes to all related forecasts
93
85
  # - cascade_session - will cascade deletes to all related sessions
94
86
  # - cascade_view - will cascade deletes to all related views (any part of join - think twice)
87
+ # - cascase_model - will cascade deletes to all models created from this dataset
95
88
  # - cascade - will cascade deletes to all related forecasts and sessions
96
89
  # @example - request delete with cascade forecast
97
90
  # NexosisApi.client.remove_dataset('mydataset', {:cascade_forecast => true})
@@ -105,16 +98,13 @@ module NexosisApi
105
98
  query['startDate'] = [filter_options[:start_date].to_s] unless filter_options[:start_date].nil?
106
99
  query['endDate'] = [filter_options[:end_date].to_s] unless filter_options[:end_date].nil?
107
100
  end
108
- #normalizer = proc { |query_set| query_set.map { |key, value| value.map { |v| "#{key}=#{v}" } }.join('&') }
101
+ # normalizer = proc { |query_set| query_set.map { |key, value| value.map { |v| "#{key}=#{v}" } }.join('&') }
109
102
  response = self.class.delete(dataset_remove_url,
110
103
  headers: @headers,
111
104
  query: query,
112
105
  query_string_normalizer: ->(query_map) {array_query_normalizer(query_map)})
113
- if response.success?
114
- return
115
- else
116
- raise HttpException.new("There was a problem removing the dataset: #{response.code}.", "removing dataset #{dataset_name}", response)
117
- end
106
+ return if response.success?
107
+ raise HttpException.new("There was a problem removing the dataset: #{response.code}.", "removing dataset #{dataset_name}", response)
118
108
  end
119
109
 
120
110
  private
@@ -146,7 +136,7 @@ module NexosisApi
146
136
  # @private
147
137
  def create_cascade_options(option_hash)
148
138
  return nil if option_hash.nil?
149
- return %w[session view forecast] if option_hash.key?(:cascade)
139
+ return %w[session view forecast model] if option_hash.key?(:cascade)
150
140
  options_set = []
151
141
  option_hash.each_key { |k| options_set << k.to_s.gsub(/cascade_/, '') if k.to_s.include? 'cascade_' }
152
142
  # HACK: required to be backward compatible with incorrect key names
@@ -10,16 +10,12 @@ module NexosisApi
10
10
  #
11
11
  # @return [Array of NexosisApi::ImportsResponse]
12
12
  def list_imports
13
- imports_url = "/imports"
14
- response = self.class.get(imports_url, :headers => @headers)
15
- if(response.success?)
16
- items = []
17
- response.parsed_response["items"].each do |i|
18
- items << NexosisApi::ImportsResponse.new(i)
19
- end
20
- items
13
+ imports_url = '/imports'
14
+ response = self.class.get(imports_url, headers: @headers)
15
+ if (response.success?)
16
+ response.parsed_response['items'].map { |i| NexosisApi::ImportsResponse.new(i) }
21
17
  else
22
- raise HttpException.new("There was a problem getting the imports: #{response.code}.", "uploading dataset from s3 #{dataset_name}" ,response)
18
+ raise HttpException.new("There was a problem getting the imports: #{response.code}.", "uploading dataset from s3 #{dataset_name}", response)
23
19
  end
24
20
  end
25
21
 
@@ -32,21 +28,21 @@ module NexosisApi
32
28
  # @param column_metadata [Array of NexosisApi::Column] description of each column in target dataset. Optional.
33
29
  # @return [NexosisApi::ImportsResponse]
34
30
  # @see http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region for information on region names
35
- def import_from_s3(dataset_name, bucket_name, path, region = "us-east-1", column_metadata = [])
36
- raise ArgumentError, "dataset_name was not provided and is not optional " unless dataset_name.to_s.empty? == false
37
- raise ArgumentError, "bucket_name was not provided and is not optional " unless bucket_name.to_s.empty? == false
38
- raise ArgumentError, "path was not provided and is not optional " unless path.to_s.empty? == false
39
- s3_import_url = "/imports/s3"
31
+ def import_from_s3(dataset_name, bucket_name, path, region = 'us-east-1', column_metadata = [])
32
+ raise ArgumentError, 'dataset_name was not provided and is not optional ' unless dataset_name.to_s.empty? == false
33
+ raise ArgumentError, 'bucket_name was not provided and is not optional ' unless bucket_name.to_s.empty? == false
34
+ raise ArgumentError, 'path was not provided and is not optional ' unless path.to_s.empty? == false
35
+ s3_import_url = '/imports/s3'
40
36
  column_json = Column.to_json(column_metadata)
41
37
  body = {
42
- "dataSetName" => dataset_name,
43
- "bucket" => bucket_name,
44
- "path" => path,
45
- "region" => region,
46
- "columns" => column_json
38
+ 'dataSetName' => dataset_name,
39
+ 'bucket' => bucket_name,
40
+ 'path' => path,
41
+ 'region' => region,
42
+ 'columns' => column_json
47
43
  }
48
- response = self.class.post(s3_import_url, :headers => @headers, :body => body.to_json)
49
- if(response.success?)
44
+ response = self.class.post(s3_import_url, headers: @headers, body: body.to_json)
45
+ if (response.success?)
50
46
  NexosisApi::ImportsResponse.new(response.parsed_response)
51
47
  else
52
48
  raise HttpException.new("There was a problem importing from s3: #{response.code}.", "uploading dataset from s3 #{dataset_name}" ,response)
@@ -60,10 +56,10 @@ module NexosisApi
60
56
  # @example get S3 import
61
57
  # NexosisApi.client.retrieve_import('740dca2a-b488-4322-887e-fa473b1caa54')
62
58
  def retrieve_import(import_id)
63
- raise ArgumentError, "import_id was not provided and is not optional " unless import_id.to_s.empty? == false
59
+ raise ArgumentError, 'import_id was not provided and is not optional ' unless import_id.to_s.empty? == false
64
60
  imports_url = "/imports/#{import_id}"
65
- response = self.class.get(imports_url, :headers => @headers)
66
- if(response.success?)
61
+ response = self.class.get(imports_url, headers: @headers)
62
+ if (response.success?)
67
63
  NexosisApi::ImportsResponse.new(response.parsed_response)
68
64
  else
69
65
  raise HttpException.new("There was a problem getting the import #{response.code}.", "requesting an import #{import_id}" ,response)
@@ -0,0 +1,107 @@
1
+ module NexosisApi
2
+ class Client
3
+ # class to operate on model endpoint in Nexosis API
4
+ # @since 1.3.0
5
+ module Models
6
+ # List all models created in your company, optionally filtered by query parameters
7
+ #
8
+ # @param datasource_name [String] optionally limit to those
9
+ # models created for this data source name.
10
+ # @param query_options [Hash] limit by dates: begin_date and/or end_date
11
+ # @note - query options dates can either be ISO 8601 compliant strings or Date objects
12
+ # @return [Array of NexosisApi::ModelSummary] - all models available within the query parameters
13
+ def list_models(datasource_name = nil, page = 0, page_size = 50, query_options = {})
14
+ model_url = '/models'
15
+ query = {
16
+ page: page,
17
+ pageSize: page_size
18
+ }
19
+ unless query_options.empty?
20
+ query.store('createdBeforeDate', query_options['end_date']) unless query_options['end_date'].nil?
21
+ query.store('createdAfterDate', query_options['begin_date']) unless query_options['begin_date'].nil?
22
+ end
23
+ query.store(dataSourceName: datasource_name) unless datasource_name.nil?
24
+ response = self.class.get(model_url, headers: @headers, query: query)
25
+ if (response.success?)
26
+ response.parsed_response['items'].map { |item| NexosisApi::ModelSummary.new(item) }
27
+ else
28
+ raise HttpException.new("There was a problem listing models: #{response.code}.", "listing models with data source name #{datasource_name}", response)
29
+ end
30
+ end
31
+
32
+ # Get the details of the particular model requested by id
33
+ #
34
+ # @param model_id [String] The unique identifier for the model returned by a create-model session
35
+ # @return [NexosisApi::ModelSummary]
36
+ def get_model(model_id)
37
+ raise ArgumentError, 'Retrieving a model requires that model_id be specified and it is currently null.' if model_id.nil?
38
+ model_url = "/models/#{model_id}"
39
+ response = self.class.get(model_url, @options)
40
+ if (response.success?)
41
+ NexosisApi::ModelSummary.new(response.parsed_response)
42
+ else
43
+ raise HttpException.new("There was a problem getting your model: #{response.code}.", "Could not get model #{model_id}", response)
44
+ end
45
+ end
46
+
47
+ # Run a feature set through the model to get predictions
48
+ #
49
+ # @param model_id [String] unique identifier of model to use
50
+ # @param feature_data [Array of Hash] feature columns with values to predict from
51
+ # @return [NexosisApi::PredictResponse]
52
+ # @note The feature data shape should match that of the dataset used to create the model.
53
+ # Any missing features in this request will reduce the quality of the predictions.
54
+ def predict(model_id, feature_data)
55
+ raise ArgumentError, 'Running predictions requires that model_id be specified and it is currently empty.' if model_id.empty?
56
+ raise ArgumentError, 'Running predictions requires that feature_data be specified and it is currently empty.' if feature_data.empty?
57
+ predict_url = "/models/#{model_id}/predict"
58
+ response = self.class.post(predict_url, headers: @headers, body: { "data": feature_data }.to_json)
59
+ if (response.success?)
60
+ NexosisApi::PredictResponse.new(model_id, response.parsed_response)
61
+ else
62
+ raise HttpException.new("There was a problem predicting from your model: #{response.code}.",
63
+ "Could not start predict for #{model_id}",
64
+ response)
65
+ end
66
+ end
67
+
68
+ # Remove an existing model
69
+ #
70
+ # @param model_id [String] the unique id of the model to remove.
71
+ def remove_model(model_id)
72
+ raise ArgumentError, 'Deleting a model requires that model_id be specified and it is currently empty.' if model_id.empty?
73
+ delete_url = "/models/#{model_id}"
74
+ response = self.class.delete(delete_url, @options)
75
+ unless (response.success?)
76
+ raise HttpException.new("There was a problem deleting your model: #{response.code}.",
77
+ "Could not delete #{model_id}",
78
+ response)
79
+ end
80
+ end
81
+
82
+ # Deletes multiple models based on the provided filter criteria.
83
+ # @param datasource_name [String] remove all models created by this datasource
84
+ # @param begin_date [DateTime] remove all models created after this date/time - inclusive. May be a ISO 8601 compliant string.
85
+ # @param end_date [DateTime] remove all models created before this date/time - inclusive. May be a ISO 8601 compliant string.
86
+ # @note - Use with great care. This permanently removes trained models.
87
+ # All parameters are indepdently optional, but one must be sent.
88
+ def remove_models(datasource_name = nil, begin_date = nil, end_date = nil)
89
+ params_unset = datasource_name.nil?
90
+ params_unset &= begin_date.nil?
91
+ params_unset &= end_date.nil?
92
+ raise ArgumentError, 'Must set one of the method parameters.' if params_unset
93
+ delete_url = '/models'
94
+ query = {}
95
+ query.store('dataSourceName', datasource_name) unless datasource_name.nil?
96
+ query.store('createdAfterDate', begin_date) unless begin_date.nil?
97
+ query.store('createdBeforeDate', end_date) unless end_date.nil?
98
+ response = self.class.delete(delete_url, headers: @headers, query: query)
99
+ unless (response.success?)
100
+ raise HttpException.new("There was a problem deleting your models: #{response.code}.",
101
+ 'Could not delete models',
102
+ response)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -45,21 +45,18 @@ module NexosisApi
45
45
  # Remove a session
46
46
  # @param session_id [String] required session identifier
47
47
  def remove_session(session_id)
48
- if(session_id.to_s.empty?)
48
+ if (session_id.to_s.empty?)
49
49
  raise ArgumentError 'session_id cannot be empty or nil'
50
50
  end
51
51
  session_url = "/sessions/#{session_id}"
52
52
  response = self.class.delete(session_url, headers: @headers)
53
- if(response.success?)
54
- return
55
- else
56
- raise HttpException.new('Could not delete session with given id', "remove session with id #{session_id.to_s}",response)
57
- end
53
+ return if response.success?
54
+ raise HttpException.new('Could not delete session with given id', "remove session with id #{session_id}", response)
58
55
  end
59
56
 
60
57
  # Remove sessions that have been run. All query options are optional and will be used to limit the sessions removed.
61
- # @param query_options [Hash] optionally provide query parametes to limit the set of sessions removed.
62
- # @note query parameters hash members are type, dataset_name, event_name, start_date, and end_date.
58
+ # @param query_options [Hash] optionally provide query parametes to limit the set of sessions removed.
59
+ # @note query parameters hash members are type, dataset_name, event_name, start_date, and end_date.
63
60
  # Start and end dates refer to the session requested date.
64
61
  # Results are not removed but then can only be accessed by dataset name
65
62
  # @example Remove all sessions based on a dataset by name
@@ -67,25 +64,22 @@ module NexosisApi
67
64
  def remove_sessions(query_options = {})
68
65
  sessions_url = '/sessions'
69
66
  response = self.class.delete(sessions_url, :headers => @headers, :query => get_query_from_options(query_options))
70
- if(response.success?)
71
- return
72
- else
73
- raise HttpException.new('Could not remove sessions', "Remove sessions with query #{query_options.to_s}",response)
74
- end
67
+ return if response.success?
68
+ raise HttpException.new('Could not remove sessions', "Remove sessions with query #{query_options.to_s}",response)
75
69
  end
76
70
 
77
71
  # Initiate a new forecast session based on a named dataset.
78
72
  #
79
73
  # @param dataset_name [String] The name of the saved data set that has the data to forecast on.
80
- # @param start_date [DateTime] The starting date of the forecast period. Can be ISO 8601 string.
74
+ # @param start_date [DateTime] The starting date of the forecast period. Can be ISO 8601 string.
81
75
  # @param end_date [DateTime] The ending date of the forecast period. Can be ISO 8601 string.
82
76
  # @param target_column [String] The name of the column for which you want predictions. Nil if defined in dataset.
83
77
  # @param result_interval [NexosisApi::TimeInterval] (optional) - The date/time interval (e.g. Day, Hour) at which predictions should be generated. So, if Hour is specified for this parameter you will get a Result record for each hour between startDate and endDate. If unspecified, we’ll generate predictions at a Day interval.
84
- # @param column_metadata [Array of NexosisApi::Column] (optional) - specification for how to handle columns if different from existing metadata on dataset
78
+ # @param column_metadata [Array of NexosisApi::Column] (optional) - specification for how to handle columns if different from existing metadata on dataset
85
79
  # @return [NexosisApi::SessionResponse] providing information about the sesssion
86
80
  # @note The time interval selected must be greater than or equal to the finest granularity of the data provided.
87
81
  # For instance if your data includes many recoreds per hour, then you could request hour, day, or any other result interval.
88
- # However, if your data includes only a few records per day or fewer, then a request for an hourly result interval will produce poor results.
82
+ # However, if your data includes only a few records per day or fewer, then a request for an hourly result interval will produce poor results.
89
83
  def create_forecast_session(dataset_name, start_date, end_date, target_column = nil, result_interval = NexosisApi::TimeInterval::DAY, column_metadata = nil)
90
84
  create_session(dataset_name, start_date, end_date, target_column, false, nil, 'forecast', result_interval, column_metadata)
91
85
  end
@@ -136,18 +130,13 @@ module NexosisApi
136
130
  # @return [NexosisApi::SessionResult] SessionResult if parsed, String of csv data otherwise
137
131
  def get_session_results(session_id, as_csv = false)
138
132
  session_result_url = "/sessions/#{session_id}/results"
139
- if as_csv
140
- @headers["Accept"] = 'text/csv'
141
- end
133
+ @headers['Accept'] = 'text/csv' if as_csv
142
134
  response = self.class.get(session_result_url, @options)
143
135
  @headers.delete('Accept')
144
136
 
145
- if(response.success?)
146
- if(as_csv)
147
- response.body
148
- else
149
- NexosisApi::SessionResult.new(response.parsed_response)
150
- end
137
+ if (response.success?)
138
+ return response.body if as_csv
139
+ NexosisApi::SessionResult.new(response.parsed_response)
151
140
  else
152
141
  raise HttpException.new("There was a problem getting the session: #{response.code}.", "get results for session #{session_id}" ,response)
153
142
  end
@@ -160,17 +149,34 @@ module NexosisApi
160
149
  def get_session(session_id)
161
150
  session_url = "/sessions/#{session_id}"
162
151
  response = self.class.get(session_url, @options)
163
- if(response.success?)
164
- NexosisApi::Session.new(response.parsed_response)
152
+ return NexosisApi::Session.new(response.parsed_response) if response.success?
153
+ raise HttpException.new("There was a problem getting the session: #{response.code}.", "getting session #{session_id}" ,response)
154
+ end
155
+
156
+ def create_model(datasource_name, target_column, columns = {})
157
+ model_url = '/sessions/model'
158
+ body = {
159
+ dataSourceName: datasource_name,
160
+ targetColumn: target_column,
161
+ predictionDomain: 'regression',
162
+ isEstimate: false
163
+ }
164
+ body.store(columns: columns) unless columns.empty?
165
+ response = self.class.post(model_url, headers: @headers, body: body.to_json)
166
+ if response.success?
167
+ session_hash = { 'session' => response.parsed_response }.merge(response.headers)
168
+ NexosisApi::SessionResponse.new(session_hash)
165
169
  else
166
- raise HttpException.new("There was a problem getting the session: #{response.code}.", "getting session #{session_id}" ,response)
170
+ raise HttpException.new("There was a problem creating the model session: #{response.code}.", 'creating model session' ,response)
167
171
  end
168
- end
172
+ end
169
173
 
170
174
  private
171
- def create_session(dataset_name, start_date, end_date, target_column = nil, is_estimate=false, event_name = nil, type = "forecast", result_interval = NexosisApi::TimeInterval::DAY, column_metadata = nil)
175
+
176
+ # @private
177
+ def create_session(dataset_name, start_date, end_date, target_column = nil, is_estimate=false, event_name = nil, type = 'forecast', result_interval = NexosisApi::TimeInterval::DAY, column_metadata = nil)
172
178
  session_url = "/sessions/#{type}"
173
- query = {
179
+ query = {
174
180
  'targetColumn' => target_column.to_s,
175
181
  'startDate' => start_date.to_s,
176
182
  'endDate' => end_date.to_s,
@@ -178,20 +184,20 @@ module NexosisApi
178
184
  'resultInterval' => result_interval.to_s
179
185
  }
180
186
  query['dataSetName'] = dataset_name.to_s unless dataset_name.to_s.empty?
181
- if(event_name.nil? == false)
187
+ if (event_name.nil? == false)
182
188
  query['eventName'] = event_name
183
189
  end
184
190
  body = ''
185
- if(column_metadata.nil? == false)
191
+ if (column_metadata.nil? == false)
186
192
  column_json = Column.to_json(column_metadata)
187
193
  body = {
188
194
  'dataSetName' => dataset_name,
189
195
  'columns' => column_json
190
196
  }
191
197
  end
192
- response = self.class.post(session_url, :headers => @headers, :query => query, :body => body.to_json)
193
- if(response.success?)
194
- session_hash = {'session' => response.parsed_response}.merge(response.headers)
198
+ response = self.class.post(session_url, headers: @headers, query: query, body: body.to_json)
199
+ if (response.success?)
200
+ session_hash = { 'session' => response.parsed_response }.merge(response.headers)
195
201
  NexosisApi::SessionResponse.new(session_hash)
196
202
  else
197
203
  raise HttpException.new("Unable to create new #{type} session", "Create session for dataset #{dataset_name}",response)
@@ -12,5 +12,9 @@ module NexosisApi
12
12
 
13
13
  # A feature to be included in analysis
14
14
  FEATURE = :feature
15
+
16
+ # This column will be used to uniquely identify rows during
17
+ # update and delete operations, but will not be used as a feature.
18
+ KEY = :key
15
19
  end
16
20
  end
@@ -6,9 +6,7 @@ module NexosisApi
6
6
  if (k == 'data')
7
7
  @data = v
8
8
  elsif (k == 'links')
9
- links = Array.new
10
- v.each do |l| links << NexosisApi::Link.new(l) end
11
- @links = links
9
+ @links = v.reject(&:nil?).map { |l| NexosisApi::Link.new(l) }
12
10
  end
13
11
  end
14
12
  end
@@ -17,7 +15,7 @@ module NexosisApi
17
15
  # @return [Array of NexosisApi::Link]
18
16
  attr_accessor :links
19
17
 
20
- #The hash of data values from the dataset
18
+ # The hash of data values from the dataset
21
19
  # @return [Array of Hash] where each hash contains the dataset data
22
20
  attr_accessor :data
23
21
  end
@@ -3,15 +3,13 @@ module NexosisApi
3
3
  class DatasetSummary
4
4
  def initialize(data_hash)
5
5
  data_hash.each do |k, v|
6
- if(k == 'dataSetName')
6
+ if (k == 'dataSetName')
7
7
  @dataset_name = v unless v.nil?
8
- elsif(k == 'columns')
9
- columns = []
10
- next if v.nil?
11
- v.keys.each do |col_key|
12
- columns << NexosisApi::Column.new(col_key, v[col_key])
13
- end
14
- @column_metadata = columns
8
+ elsif (k == 'columns')
9
+ @column_metadata = v.reject { |_key, value| value.nil? }
10
+ .map do |col_key, col_val|
11
+ NexosisApi::Column.new(col_key, col_val)
12
+ end
15
13
  end
16
14
  end
17
15
  end
@@ -23,5 +21,13 @@ module NexosisApi
23
21
  # Descriptive information about the columns
24
22
  # @return [Array of NexosisApi::Column]
25
23
  attr_accessor :column_metadata
24
+
25
+ # Helper method which tells you whether or not this dataset has a column with timestamp role.
26
+ # @note Often helpful for implmenters as non-timeseries datasets
27
+ # cannot be sent to forecast or impact sessions
28
+ # @since 1.3.0
29
+ def timeseries?
30
+ !@column_metadata.select { |dc| dc.role == NexosisApi::ColumnRole::TIMESTAMP }.empty?
31
+ end
26
32
  end
27
33
  end
@@ -18,6 +18,8 @@ module NexosisApi
18
18
  links = []
19
19
  v.each { |l| links << NexosisApi::Link.new(l) }
20
20
  instance_variable_set("@#{k}", links) unless v.nil?
21
+ elsif k == 'dataSetName'
22
+ @datasource_name = v
21
23
  else
22
24
  instance_variable_set("@#{k}", v) unless v.nil?
23
25
  end
@@ -37,10 +39,21 @@ module NexosisApi
37
39
  # @note The import will be performed in a FIFO queue. Check back on status before attempting to start a session using the dataset.
38
40
  attr_accessor :status
39
41
 
42
+ # Date and status of each status this session has entered
43
+ # @return [Hash]
44
+ # @since 1.3.0
45
+ attr_accessor :statusHistory
46
+
40
47
  # echo back the dataset name provided
41
48
  # @return [String]
49
+ # @deprecated use datasource_name instead
42
50
  attr_accessor :dataSetName
43
51
 
52
+ # echo back the name of the data source uploaded
53
+ # @return [String]
54
+ # @since 1.3.0
55
+ attr_accessor :datasource_name
56
+
44
57
  # The S3 parameters used to import a dataset
45
58
  # @return [Hash]
46
59
  # For an S3 response the keys of this hash should be 'bucket', 'path', and 'region'
@@ -0,0 +1,66 @@
1
+ module NexosisApi
2
+ # class to hold the parsed results of model summary json
3
+ # @since 1.3.0
4
+ class ModelSummary
5
+ def initialize(model_hash)
6
+ model_hash.each do |k, v|
7
+ k = k.to_s
8
+ if (k == 'modelId')
9
+ @model_id = v
10
+ elsif (k == 'predictionDomain')
11
+ @prediction_domain = v
12
+ elsif (k == 'dataSourceName')
13
+ @datasource_name = v
14
+ elsif (k == 'createdDate')
15
+ @created_date = DateTime.parse(v) unless v.nil?
16
+ elsif (k == 'algorithm')
17
+ @algorithm = NexosisApi::Algorithm.new(v) unless v.nil?
18
+ elsif (k == 'columns')
19
+ @column_metadata = v.reject { |_key, value| value.nil? }
20
+ .map do |col_key, col_val|
21
+ NexosisApi::Column.new(col_key, col_val)
22
+ end
23
+ elsif (k == 'metrics')
24
+ @metrics = v.reject { |_key, value| value.nil? }
25
+ .map do |col_key, col_val|
26
+ NexosisApi::Metric.new(name: col_key, value: col_val)
27
+ end
28
+ elsif (k == 'sessionId')
29
+ @session_id = v
30
+ end
31
+ end
32
+ end
33
+
34
+ # Unique model id for this model in uuid/guid format.
35
+ # @return [String]
36
+ attr_accessor :model_id
37
+
38
+ # Unique id of the session used to create this model instance
39
+ # @return [String]
40
+ attr_accessor :session_id
41
+
42
+ # The type of prediction performed
43
+ # @return [String]
44
+ attr_reader :prediction_domain
45
+
46
+ # The data source used to create this model
47
+ # @return [String]
48
+ attr_accessor :datasource_name
49
+
50
+ # The date on which this model was created.
51
+ # @return [DateTime]
52
+ attr_accessor :created_date
53
+
54
+ # Information about the algorithm used to create the model
55
+ # @return [NexosisApi::Algorithm]
56
+ attr_accessor :algorithm
57
+
58
+ # Descriptive information about the columns
59
+ # @return [Array of NexosisApi::Column]
60
+ attr_accessor :column_metadata
61
+
62
+ # Algorithm and model specific metrics which may be of interest
63
+ # @return [Array of NexosisApi::Metric]
64
+ attr_accessor :metrics
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ module NexosisApi
2
+ # Class to hold the parsed response of a prediction request
3
+ # @since 1.3.0
4
+ class PredictResponse
5
+ def initialize(model_id, response_hash)
6
+ @model_id = model_id
7
+ @predictions = response_hash['data']
8
+ @message = response_hash['messages']
9
+ end
10
+
11
+ # The unique identifier for the model used to create these predictions
12
+ # @return [String]
13
+ attr_reader :model_id
14
+
15
+ # The feature data along with predicted target value
16
+ # @return [Array of Hash] each row of data as a hash in an array of values
17
+ # @note The result data includes an echo of the data sent to the predict request
18
+ # along with the target column containing the values predicted.
19
+ # [
20
+ # {
21
+ # "feature1": 23.33,
22
+ # "target": 2.59
23
+ # },
24
+ # {
25
+ # "feature1": 15.82,
26
+ # "target": 1.75
27
+ # }
28
+ # ]
29
+ attr_accessor :predictions
30
+
31
+ # A list of warning message optionally returned from prediction run
32
+ # @return [Array]
33
+ attr_accessor :messages
34
+ end
35
+ end
@@ -3,23 +3,25 @@ module NexosisApi
3
3
  class Session
4
4
  def initialize(sessionHash)
5
5
  sessionHash.each do |k,v|
6
- if(k == 'links')
6
+ if (k == 'links')
7
7
  links = Array.new
8
- v.each do |l| links << NexosisApi::Link.new(l) end
8
+ v.each { |l| links << NexosisApi::Link.new(l) }
9
9
  instance_variable_set("@#{k}", links) unless v.nil?
10
- elsif(k == 'isEstimate')
10
+ elsif (k == 'isEstimate')
11
11
  instance_variable_set('@is_estimate', v) unless v.nil?
12
- elsif(k == 'columns')
13
- columns = []
14
- next if v.nil?
15
- v.keys.each do |col_key|
16
- columns << NexosisApi::Column.new(col_key, v[col_key])
17
- end
18
- @column_metadata = columns
19
- elsif(k == 'resultInterval')
12
+ elsif (k == 'columns')
13
+ @column_metadata = v.reject { |_key, value| value.nil? }
14
+ .map do |col_key, col_val|
15
+ NexosisApi::Column.new(col_key, v[col_key])
16
+ end
17
+ elsif (k == 'resultInterval')
20
18
  @result_interval = v
21
19
  elsif (k == 'dataSourceName')
22
20
  @datasource_name = v
21
+ elsif (k == 'modelId')
22
+ @model_id = v
23
+ elsif (k == 'requestedDate')
24
+ @requested_date = DateTime.parse(v)
23
25
  else
24
26
  instance_variable_set("@#{k}", v) unless v.nil?
25
27
  end
@@ -48,7 +50,7 @@ module NexosisApi
48
50
 
49
51
  # the dataset used in this session
50
52
  # @return [String]
51
- # @deprecated - Use the @data_source_name property instead
53
+ # @deprecated - Use the @datasource_name property instead
52
54
  attr_accessor :dataSetName
53
55
 
54
56
  # The column in the dataset for which this session ran predictions
@@ -84,5 +86,17 @@ module NexosisApi
84
86
  # @return [String] - the dataset or view name
85
87
  # @since 1.2.0
86
88
  attr_accessor :datasource_name
89
+
90
+ # The date this session was orginally submitted
91
+ # @since 1.3.0
92
+ attr_accessor :requested_date
93
+
94
+ # The id of the model created by this session if any
95
+ # @return [String] a uuid/buid format unique string for the model
96
+ # @since 1.3.0
97
+ # @note This is always empty in time-series sessions (forecast/impact)
98
+ # The model id returned here should be used in all future calls
99
+ # to model endpoints - primarily the /models/{modelId}/predict endpoint.
100
+ attr_accessor :model_id
87
101
  end
88
102
  end
@@ -3,13 +3,15 @@ module NexosisApi
3
3
  class SessionResult < Session
4
4
  def initialize(session_hash)
5
5
  session_hash.each do |k, v|
6
- if k == 'metrics'
7
- instance_variable_set("@#{k}", NexosisApi::ImpactMetric.new(v)) unless v.nil?
8
- else
9
- instance_variable_set("@#{k}", v) unless v.nil?
6
+ if k.to_s == 'metrics' && session_hash['type'] == 'impact'
7
+ instance_variable_set("@#{k}", NexosisApi::ImpactMetric.new(v)) unless v.nil?
8
+ elsif k.to_s == 'metrics'
9
+ @metrics = v.map { |key, value| NexosisApi::Metric.new( { 'name' => key.to_s, 'value' => value } ) } unless v.nil?
10
+ elsif k.to_s == 'data'
11
+ @data = v
10
12
  end
11
13
  end
12
- super(session_hash.reject { |k,v| k == 'data' || k == 'metrics' })
14
+ super(session_hash.reject { |k, _v| k.to_s == 'data' || k.to_s == 'metrics' })
13
15
  end
14
16
 
15
17
  # The impact analysis if this session type is impact
@@ -17,7 +19,9 @@ module NexosisApi
17
19
  attr_accessor :metrics
18
20
 
19
21
  # The result data in a hash with the name of the target column
20
- # @return [Hash]
22
+ # @return [Array of Hash]
23
+ # @note When retrieving a model creation session this field
24
+ # will contain the test data and results.
21
25
  attr_accessor :data
22
26
  end
23
27
  end
@@ -14,6 +14,8 @@ module NexosisApi
14
14
  elsif k == 'joins'
15
15
  next if v.nil?
16
16
  @joins = v.reject(&:nil?).map { |join| NexosisApi::Join.new(join) }
17
+ elsif k == 'isTimeSeries'
18
+ @is_timeseries = v
17
19
  end
18
20
  end
19
21
  end
@@ -34,6 +36,14 @@ module NexosisApi
34
36
  # @return [Array of NexosisApi::Join]
35
37
  attr_accessor :joins
36
38
 
39
+ # Is this view based on time series data?
40
+ # @since 1.3.0
41
+ attr_accessor :is_timeseries
42
+
43
+ # Is this view based on time series data?
44
+ # @since 1.3.0
45
+ alias_method :timeseries?, :is_timeseries
46
+
37
47
  def to_json
38
48
  hash = {}
39
49
  hash['dataSetName'] = dataset_name
@@ -16,6 +16,6 @@ Gem::Specification.new do |spec|
16
16
  spec.require_paths = ['lib']
17
17
  spec.required_ruby_version = '>= 2.0.0'
18
18
  spec.summary = "Ruby client for working with the Nexosis API"
19
- spec.version = '1.2.4'
19
+ spec.version = '1.3.0'
20
20
  spec.metadata["yard.run"] = "yri"
21
21
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexosis_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nexosis,Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-20 00:00:00.000000000 Z
11
+ date: 2017-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,6 +53,7 @@ files:
53
53
  - lib/nexosis_api/client.rb
54
54
  - lib/nexosis_api/client/datasets.rb
55
55
  - lib/nexosis_api/client/imports.rb
56
+ - lib/nexosis_api/client/models.rb
56
57
  - lib/nexosis_api/client/sessions.rb
57
58
  - lib/nexosis_api/client/views.rb
58
59
  - lib/nexosis_api/column.rb
@@ -69,6 +70,8 @@ files:
69
70
  - lib/nexosis_api/join.rb
70
71
  - lib/nexosis_api/link.rb
71
72
  - lib/nexosis_api/metric.rb
73
+ - lib/nexosis_api/model_summary.rb
74
+ - lib/nexosis_api/predict_response.rb
72
75
  - lib/nexosis_api/session.rb
73
76
  - lib/nexosis_api/session_response.rb
74
77
  - lib/nexosis_api/session_result.rb