فهرست منبع

HUE-3570 [notebook] Skeleton for Solr SQL snippet

Romain Rigaux 9 سال پیش
والد
کامیت
1162b24

+ 4 - 1
desktop/conf.dist/hue.ini

@@ -652,6 +652,10 @@
       name = Oracle
       interface=rdbms
 
+    [[[solr]]]
+      name = Solr Search
+      interface=solr
+
     # [[[mysql]]]
     #   name=MySql JDBC
     #   interface=jdbc
@@ -660,7 +664,6 @@
     #   ## If 'user' and 'password' are omitted, they will be prompted in the UI.
     #   options='{"url": "jdbc:mysql://localhost:3306/hue", "driver": "com.mysql.jdbc.Driver", "user": "root", "password": "root"}'
 
-
   ## Main flag to override the automatic starting of the DBProxy server.
   # enable_dbproxy_server=true
 

+ 4 - 0
desktop/conf/pseudo-distributed.ini.tmpl

@@ -656,6 +656,10 @@
       name = Oracle
       interface=rdbms
 
+    [[[solr]]]
+      name = Solr Search
+      interface=solr
+
     # [[[mysql]]]
     #   name=MySql JDBC
     #   interface=jdbc

+ 15 - 0
desktop/libs/libsolr/src/libsolr/api.py

@@ -727,6 +727,21 @@ class SolrApi(object):
     except RestException, e:
       raise PopupException(e, title=_('Error while accessing Solr'))
 
+  def sql(self, collection, statement):
+    try:
+      params = self._get_params() + (
+          ('wt', 'json'),
+          ('rows', 0),
+          ('stmt', statement),
+          ('rows', 100),
+          ('start', 0),
+      )
+
+      response = self._root.get('%(collection)s/sql' % {'collection': collection}, params=params)
+      return self._get_json(response)
+    except RestException, e:
+      raise PopupException(e, title=_('Error while accessing Solr'))
+
   def get(self, core, doc_id):
     try:
       params = self._get_params() + (

+ 3 - 0
desktop/libs/notebook/src/notebook/conf.py

@@ -137,6 +137,9 @@ def _default_interpreters():
       ('pig', {
           'name': 'Pig', 'interface': 'pig', 'options': {}
       }),
+      ('solr', {
+          'name': 'Solr', 'interface': 'solr', 'options': {}
+      }),
       ('text', {
           'name': 'Text', 'interface': 'text', 'options': {}
       }),

+ 3 - 0
desktop/libs/notebook/src/notebook/connectors/base.py

@@ -85,6 +85,7 @@ def get_api(request, snippet):
   from notebook.connectors.jdbc import JdbcApi
   from notebook.connectors.rdbms import RdbmsApi
   from notebook.connectors.pig_batch import PigApi
+  from notebook.connectors.solr import SolrApi
   from notebook.connectors.spark_shell import SparkApi
   from notebook.connectors.spark_batch import SparkBatchApi
   from notebook.connectors.text import TextApi
@@ -107,6 +108,8 @@ def get_api(request, snippet):
     return RdbmsApi(request.user, interpreter=snippet['type'])
   elif interface == 'jdbc':
     return JdbcApi(request.user, interpreter=interpreter)
+  elif interface == 'solr':
+    return SolrApi(request.user, interpreter=interpreter)  
   elif interface == 'pig':
     return PigApi(user=request.user, request=request)
   else:

+ 176 - 0
desktop/libs/notebook/src/notebook/connectors/solr.py

@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+
+from desktop.lib.exceptions_renderable import PopupException
+from desktop.lib.i18n import force_unicode
+
+from libsolr.api import SolrApi as NativeSolrApi
+
+from notebook.connectors.base import Api, QueryError
+
+
+LOG = logging.getLogger(__name__)
+
+
+def query_error_handler(func):
+  def decorator(*args, **kwargs):
+    try:
+      return func(*args, **kwargs)
+    except Exception, e:
+      message = force_unicode(str(e))
+      raise QueryError(message)
+  return decorator
+
+
+class SolrApi(Api):
+
+  def __init__(self, user, interpreter=None):
+    Api.__init__(self, user, interpreter=interpreter)
+    self.options = interpreter['options']
+
+  @query_error_handler
+  def execute(self, notebook, snippet):
+    from search.conf import SOLR_URL
+    collection = 'gettingstarted' #self.options['collection']
+
+    response = NativeSolrApi(SOLR_URL.get(), self.user.username).sql(collection, snippet['statement'])
+
+    info = response['result-set']['docs'].pop(-1) # EOF, RESPONSE_TIME
+
+    data = [[cell for cell in doc.values()] for doc in response['result-set']['docs']]
+    has_result_set = data is not None
+
+    return {
+      'sync': True,
+      'has_result_set': has_result_set,
+      'modified_row_count': 0,
+      'result': {
+        'has_more': False,
+        'data': data if has_result_set else [],
+        'meta': [{
+          'name': col,
+          'type': '',
+          'comment': ''
+        } for col in response['result-set']['docs'][0].keys()] if has_result_set else [],
+        'type': 'table'
+      }
+    }
+
+
+  @query_error_handler
+  def check_status(self, notebook, snippet):
+    return {'status': 'available'}
+
+
+  @query_error_handler
+  def fetch_result(self, notebook, snippet, rows, start_over):
+    return {
+      'has_more': False,
+      'data': [],
+      'meta': [],
+      'type': 'table'
+    }
+
+
+  @query_error_handler
+  def fetch_result_metadata(self):
+    pass
+
+
+  @query_error_handler
+  def cancel(self, notebook, snippet):
+    return {'status': 0}
+
+
+  @query_error_handler
+  def get_log(self, notebook, snippet, startFrom=None, size=None):
+    return 'No logs'
+
+
+  def download(self, notebook, snippet, format):
+    raise PopupException('Downloading is not supported yet')
+
+
+  @query_error_handler
+  def close_statement(self, snippet):
+    return {'status': -1}
+
+
+  @query_error_handler
+  def autocomplete(self, snippet, database=None, table=None, column=None, nested=None):
+    assist = Assist(solr)
+    response = {'status': -1}
+
+    if database is None:
+      response['databases'] = ['gettingstarted']
+    elif table is None:
+      tables_meta = []
+      for t in assist.get_tables(database):
+        tables_meta.append({'name': t, 'type': 'Table', 'comment': ''})
+      response['tables_meta'] = tables_meta
+    else:
+      columns = assist.get_columns(database, table)
+      response['columns'] = [col['name'] for col in columns]
+      response['extended_columns'] = columns
+
+    response['status'] = 0
+    return response
+
+
+  @query_error_handler
+  def get_sample_data(self, snippet, database=None, table=None, column=None):
+    db = NativeSolrApi(SOLR_URL.get(), self.user)
+
+    assist = Assist(self.user, db)
+    response = {'status': -1}
+
+    sample_data = assist.get_sample_data(database, table, column)
+
+    if sample_data:
+      response['status'] = 0
+      response['headers'] = sample_data.columns
+      response['rows'] = list(sample_data.rows())
+    else:
+      response['message'] = _('Failed to get sample data.')
+
+    return response
+
+
+class Assist():
+
+  def __init__(self, user, db):
+    self.user = user
+    self.db = db
+
+  def get_databases(self):
+    return self.db.collections2()
+
+  def get_tables(self, database, table_names=[]):
+    return self.db.collections2()
+
+  def get_columns(self, database, table):
+    return self.db.fields(table)
+
+  def get_sample_data(self, database, table, column=None):
+    from search.models import Collection2
+
+    collection = Collection2(user=self.user.username, name=table)
+    query = {'qs': [{'q': ''}], 'fqs': [], 'start': 0}
+
+    return self.db.query(collection, query)