質問

私は多くの異なる人々によって実行されることを期待しているサーバーを書いていますが、すべての人々が直接連絡を取ることはありません。サーバーはクラスター内で相互に通信します。サーバーの機能の一部には、潜在的に非常に大きなテーブルから行の小さなサブセットを選択することが含まれます。選択する行の正確な選択には調整が必要であり、クラスターを実行している人(たとえば、自分)が、すべてのサーバー管理者にサーバーの新しいバージョンを展開させることなく選択基準を更新できることが重要です。 。

実行時に任意のPythonコードをダウンロードして実行するサーバーを誰もインストールしたくないので、単にPythonで関数を記述することは実際にはオプションではありません。

必要なのは、この目標を達成するためにドメイン固有言語を実装する最も簡単な方法に関する提案です。この言語は、単純な式評価、およびテーブルインデックスのクエリと返された行の反復処理が可能である必要があります。言語の書きやすさと読みやすさは、その実装のしやすさに次ぐものです。また、クエリオプティマイザー全体を記述する必要がないため、クエリするインデックスを明示的に指定するものが理想的です。

これに対してコンパイルする必要のあるインターフェースは、App Engineデータストアがエクスポートするものと機能が似ています。テーブル上の任意のインデックスの連続範囲(たとえば、より小さい、より大きい、範囲、等式クエリ)、返された行をブール式でフィルタリングします。複数の独立した結果セットを連結することもできます。

この質問は、SQLを要求しているように聞こえます。ただし、このデータをサポートするデータストアがリレーショナルデータベースである必要はありません。また、SQLを自分で再実装しようとするオーバーヘッドも必要ありません。また、既知のスキーマを持つ単一のテーブルのみを扱っています。最後に、結合は必要ありません。もっとシンプルなものがはるかに望ましいでしょう。

編集:説明を展開して、誤解を解消しました。

役に立ちましたか?

解決

Pythonによって解釈されるDSLの構築。

ステップ1.ランタイムクラスとオブジェクトをビルドします。これらのクラスには、すべてのカーソルループとSQLステートメント、およびそのアルゴリズム処理がメソッドに組み込まれています。 コマンドおよびこれらのクラスを構築するための戦略デザインパターン。ほとんどのものはコマンドであり、オプションと選択肢はプラグイン戦略です。 Apache Antのタスク APIのデザインを見てください。これは良い例です。

ステップ2.このオブジェクトシステムが実際に機能することを検証します。設計がシンプルで完全であることを確認してください。テストでは、CommandおよびStrategyオブジェクトを構築してから、最上位のCommandオブジェクトを実行します。 Commandオブジェクトが作業を行います。

この時点で、ほぼ完了です。ランタイムは、上記のドメインから作成されたオブジェクトの構成にすぎません。 [これは思ったほど簡単ではありません。インスタンス化できるクラスのセットを定義してから、「クラス間で対話する」には注意が必要です。アプリケーションの作業を行います。]

あなたが持っているものは宣言だけを必要とすることに注意してください。手続きの何が問題になっていますか?手続き型要素を使用してDSLの記述を開始すると、異なる構文でPythonを記述するまで、より多くの機能が必要になることがわかります。良くない。

さらに、手続き型言語インタープリターは簡単に書くのが困難です。実行の状態、および参照の範囲は、管理が簡単です。

ネイティブPythonを使用できます。「サンドボックスから出る」ことを心配する必要はありません。確かに、短いPythonスクリプトを使用してオブジェクトを作成し、すべてを単体テストします。 PythonはDSLになります。

["しかし、待つ&quot ;、あなたは言う、「DSLの人々が任意のことを実行できるようにPythonを単に使用する場合」 PYTHONPATHとsys.pathの内容に依存します。利用できるものを制御する方法については、 site モジュールをご覧ください。]

宣言的DSLは最も単純です。それは完全に表現の練習です。一部の変数の値を設定するだけのPythonのブロックは便利です。それがDjangoの使用方法です。

ConfigParser を実行を表す言語として使用できます。オブジェクトの時間設定。

JSON または YAML 。既製のパーサーは完全に利用可能です。

XMLも使用できます。設計と解析は困難ですが、うまく機能します。人々はそれを愛しています。これが、AntとMaven(および他の多くのツール)が宣言構文を使用してプロシージャを記述する方法です。私はそれをお勧めしません、それは首の激しい痛みだからです。 Pythonを使用することをお勧めします。

または、ディープエンドから離れて独自の構文を発明し、独自のパーサーを記述することもできます。

他のヒント

ここでもう少し情報が必要になると思います。次のいずれかが誤った仮定に基づいているかどうかを教えてください。

まず、自分で指摘したように、任意のテーブルから行を選択するためのDSLが既に存在します。これは「SQL」と呼ばれます。 SQLを再発明したくないので、固定形式の単一のテーブルからクエリを実行するだけでよいと想定しています。

これが当てはまる場合は、おそらくDSLを実装する必要はありません(ただし、これは確かに1つの方法です)。オブジェクトの向きに慣れている場合は、Filterオブジェクトを作成する方が簡単かもしれません。

より具体的には、「フィルター」 1つ以上のSelectionCriterionオブジェクトを保持するコレクション。選択のタイプ(Range、LessThan、ExactMatch、Likeなど)を表す1つ以上の基本クラスから継承するようにこれらを実装できます。これらの基本クラスを配置したら、その列に適した列固有の継承バージョンを作成できます。 。最後に、サポートするクエリの複雑さに応じて、さまざまな基準間のANDおよびORおよびNOTリンケージを処理するために、何らかの種類の結合グルーを実装する必要があります。

気になる場合は、シンプルなGUIを作成してコレクションをロードできます。他に何も考えていない場合は、Excelのフィルタリングをモデルとして見ていきます。

最後に、このコレクションの内容を対応するSQLに変換し、それをデータベースに渡すのは簡単です。

ただし、目的が単純で、ユーザーがSQLを理解している場合は、WHERE句の内容を入力して、プログラムでクエリの残りの部分を作成するように単純に求めることができます。セキュリティの観点から、選択した列とFROM句をコードで制御し、データベースのアクセス許可を適切に設定し、ユーザーから送られてくる文字列に対して健全性チェックを行う場合、これは比較的安全なオプションです。

"ドメイン固有言語の実装"

"誰も実行時に任意のPythonコードをダウンロードして実行するサーバーをインストールするつもりはありません"

DSLが欲しいのですが、PythonをそのDSLにしたくないのです。はい。このDSLをどのように実行しますか? Pythonではない場合、どのランタイム が許容されますか?

Pythonインタープリターを組み込むCプログラムがある場合はどうなりますか?それは受け入れられますか?

そして-Pythonが受け入れ可能なランタイムでない場合-なぜこれにPythonタグがあるのですか?

「コンパイル」するときに言語を作成しない理由SQLまたはデータストアに必要なクエリ言語を生成しますか?

基本的に、永続化レイヤー上に抽象化を作成します。

Pythonについて言及しました。 Pythonを使用しないのはなぜですか?誰かが「入力」できる場合DSLの式、Pythonで入力できます。

式の構造にはいくつかのルールが必要ですが、新しいものを実装するよりもはるかに簡単です。

あなたは、実行時に任意のコードをダウンロードして実行するサーバーを誰もインストールしたくないと言いました。ただし、DSLは(最終的に)まさにこれを行うため、おそらくそれほど大きな違いはありません。データに非常に具体的なことをしているのでなければ、DSLがそれほどあなたを買うとは思わず、既にSQLに精通しているユーザーをいらいらさせるでしょう。引き受けるタスクのサイズを過小評価しないでください。

しかし、あなたの質問に答えるには、あなたの言語の文法、テキストを解析してツリーをたどる、コードを発行する、またはあなたが書いたAPIを呼び出す何かを考え出す必要があるでしょうあなたはまだいくつかのコードを出荷する必要があります)。

ネット上で参照できる数式の文法に関する教育テキストはたくさんありますが、それはかなり簡単です。 ANTLRやYaccなどのパーサージェネレーターツールを使用して、パーサーの生成を支援できます(またはLisp / Schemeなどの言語を使用して、2つを結合します)。適切なSQL文法を考え出すことは簡単ではありません。しかし、「BNF SQL」をグーグルで調べて、あなたが思いついたものを見てください。

幸運を祈ります。

実際にはSQLのように聞こえますが、単純に保ちたい場合は、SQLiteを試してみる価値があるでしょうか?

DSLではなく文法を作成したいようです。 ANTLR を調べると、テキストを解釈して特定のコマンドに変換する特定のパーサーを作成できます。 ANTLRは、Python、SQL、Java、C ++、C、C#などのライブラリを提供します。

また、ANTLR 計算エンジンの優れた例も作成しましたC#で

文脈自由文法は通常、構造のようなツリーを持ち、機能プログラムも構造のようなツリーを持っています。以下はすべての問題を解決するとは主張していませんが、 SQLite3 のようなものを使用したくないと確信している場合、それは方向性の良いステップです。

from functools import partial
def select_keys(keys, from_):
    return ({k : fun(v, row) for k, (v, fun) in keys.items()}
            for row in from_)

def select_where(from_, where):
    return (row for row in from_
            if where(row))

def default_keys_transform(keys, transform=lambda v, row: row[v]):
    return {k : (k, transform) for k in keys}

def select(keys=None, from_=None, where=None):
    """
    SELECT v1 AS k1, 2*v2 AS k2 FROM table WHERE v1 = a AND v2 >= b OR v3 = c

    translates to 

    select(dict(k1=(v1, lambda v1, r: r[v1]), k2=(v2, lambda v2, r: 2*r[v2])
        , from_=table
        , where= lambda r : r[v1] = a and r[v2] >= b or r[v3] = c)
    """
    assert from_ is not None
    idfunc = lambda k, t : t
    select_k = idfunc if keys is None  else select_keys
    if isinstance(keys, list):
        keys = default_keys_transform(keys)
    idfunc = lambda t, w : t
    select_w = idfunc if where is None else select_where
    return select_k(keys, select_w(from_, where))

ユーザーに任意のコードを実行する権限を与えていないことをどのように確認しますか。このフレームワークは、可能なすべての機能を許可します。さて、許容できる関数オブジェクトの固定リストを公開するセキュリティのために、その上にラッパーを正すことができます。

ALLOWED_FUNCS = [ operator.mul, operator.add, ...] # List of allowed funcs

def select_secure(keys=None, from_=None, where=None):
    if keys is not None and isinstance(keys, dict):
       for v, fun keys.values:
           assert fun in ALLOWED_FUNCS
    if where is not None:
       assert_composition_of_allowed_funcs(where, ALLOWED_FUNCS)
    return select(keys=keys, from_=from_, where=where)

assert_composition_of_allowed_funcs の書き方。 Pythonでそれを行うのは非常に困難ですが、Lispでは簡単です。 whereは where =(operator.add、(operator.getitem、row、v1)、2)または whereのような形式で評価される関数のリストであると仮定しましょう=(operator.mul、(operator.add、(opreator.getitem、row、v2)、2)、3)

これにより、 apply_lisp 関数を記述して、where関数がALLOWED_FUNCSまたはfloat、int、strなどの定数のみで構成されていることを確認できます。

def apply_lisp(where, rowsym, rowval, ALLOWED_FUNCS):
    assert where[0] in ALLOWED_FUNCS
    return apply(where[0],
          [ (apply_lisp(w, rowsym, rowval, ALLOWED_FUNCS)
            if isinstance(w, tuple)
            else rowval if w is rowsym
            else w if isinstance(w, (float, int, str))
            else None ) for w in where[1:] ])

それ以外にも、タイプをオーバーライドしたくないため、正確なタイプを確認する必要があります。したがって、 isinstance は使用せず、 type in(float、int、str)を使用してください。ああ、私たちはぶつかった:

  

Greenspunのプログラミングの第10規則:十分に複雑なもの   CまたはFortranプログラムに非公式に指定されたアドホックが含まれています   バグの多いCommon Lispの半分の遅い実装。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top