nexosis_api 1.2.4 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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