2008-09-26 7 views
5

나는 직접 접촉 할 사람이 아닌 많은 사람들이 운영 할 것으로 예상되는 서버를 작성하고 있습니다. 서버는 클러스터 내에서 서로 통신합니다. 서버의 기능 중 일부는 잠재적으로 매우 큰 테이블에서 행의 작은 하위 집합을 선택하는 것과 관련이 있습니다. 어떤 행을 선택할지에 대한 정확한 선택에는 약간의 조정이 필요하며, 모든 서버 관리자에게 새 버전의 서버를 배포하지 않고 클러스터를 실행하는 사람 (예 : 나 자신)이 선택 기준을 업데이트하는 것이 중요합니다 .테이블에서 행을 선택하기위한 도메인 특정 언어 작성하기

단순히 파이썬에서 함수를 작성하는 것은 실제로 옵션이 아닙니다. 아무도 런타임에 임의의 파이썬 코드를 다운로드하고 실행하는 서버를 설치하려고하지 않기 때문입니다.

이 목표를 달성하기 위해 도메인 특정 언어를 구현하는 가장 간단한 방법에 대한 제안이 필요합니다. 언어는 테이블 인덱스를 쿼리하고 반환 된 행을 반복 할뿐 아니라 간단한 표현식 평가가 가능해야합니다. 언어 작성 및 읽기가 쉬우므로이를 구현하기 쉽습니다. 또한 전체 쿼리 최적화 프로그램을 작성하지 않아도되므로 쿼리 할 인덱스를 명시 적으로 지정하는 것이 이상적입니다.

이 인터페이스는 컴파일해야 할 App Engine 데이터 저장소의 기능과 비슷합니다. 테이블의 모든 인덱스에서 순차적 범위를 쿼리 할 수 ​​있습니다 (예 :보다 작음,보다 큰, 범위). 등호 쿼리)를 반환 한 다음 반환 된 행을 부울 식으로 필터링합니다. 여러 개의 독립적 인 결과 세트를 함께 연결할 수도 있습니다.

이 질문은 SQL을 묻는 것처럼 들리네. 그러나이 데이터를 지원하는 데이터 저장소가 관계형 데이터베이스가되도록 요구하지 않으려 고하며 SQL을 직접 다시 구현하려는 오버 헤드가 필요하지 않습니다. 또한 알려진 스키마가있는 단일 테이블 만 처리합니다. 마지막으로 조인은 필요하지 않습니다. 훨씬 더 단순한 것이 훨씬 더 바람직 할 것입니다.

편집 : 몇 가지 오해를 정리하기 위해 설명을 확장했습니다.

+0

App Engine에 GQL을 구현 했습니까? : P – wTyeRogers

답변

4

에서 만든 ANTLR calculation engine의 좋은 예입니다.

1 단계. 런타임 클래스 및 개체를 빌드하십시오. 이 클래스는 모든 커서 루프와 SQL 문 및 해당 알고리즘 처리가 모두 해당 메서드에 숨어 있습니다. 이 클래스를 빌드하려면 CommandStrategy 디자인 패턴을 많이 사용하게됩니다. 대부분의 것은 명령이며, 옵션과 선택은 플러그인 전략입니다. Apache Ant의 디자인 인 Task API를 살펴보십시오. 좋은 예입니다.

2 단계.이 개체 시스템이 실제로 작동하는지 확인합니다. 디자인이 간단하고 완전한지 확인하십시오. 테스트는 Command 및 Strategy 객체를 생성 한 다음 최상위 Command 객체를 실행합니다. Command 개체가 작업을 수행합니다.

이 시점에서 대부분 완료되었습니다. 런타임은 위의 도메인에서 생성 된 객체의 구성 일뿐입니다. [소리가 나는 것처럼 쉽지는 않습니다. 인스턴스화 할 수있는 클래스 집합을 정의한 다음 응용 프로그램의 작업을 수행하기 위해 "대화"하는 클래스를 정의해야합니다.]

선언 내용 만 있으면됩니다. 절차상의 문제점은 무엇입니까? 하나는 절차 적 요소가있는 DSL을 작성하기 시작하면서 다른 구문으로 파이썬을 작성하기 전까지 점점 더 많은 기능이 필요하다는 것을 알게되었습니다. 안좋다.

또한 절차 언어 해석기는 작성하기가 쉽지 않습니다. 실행 상태 및 참조 범위는 관리하기가 쉽지 않습니다.

네이티브 파이썬을 사용할 수 있습니다. "샌드 박스에서 벗어나는 것에 대해 걱정하지 마세요." 사실, 그게 당신이 객체를 만들기 위해 짧은 파이썬 스크립트를 사용하여 모든 것을 단위 테스트하는 방법입니다. 파이썬은 DSL이 될 것입니다.

[ "하지만 파이썬을 단순히 DSL로 사용하면 임의의 일을 실행할 수 있습니다."라고 말합니다. PYTHONPATH 및 sys.path에있는 항목에 따라 다릅니다. 사용 가능한 기능을 제어하는 ​​방법은 site 모듈을 참조하십시오.]

선언적 DSL은 가장 간단합니다. 그것은 전적으로 표현의 연습입니다. 단순히 일부 변수의 값을 설정하는 Python 블록이 좋습니다. 그것은 장고가 사용하는 것입니다.

개체의 런타임 구성을 나타내는 언어로 ConfigParser을 사용할 수 있습니다.

개체의 런타임 구성을 나타내는 언어로 JSON 또는 YAML을 사용할 수 있습니다. 기성품 파서는 전적으로 사용할 수 있습니다.

XML도 사용할 수 있습니다. 디자인하고 파싱하는 것이 어렵지만 잘 작동합니다. 사람들은 그것을 좋아합니다. Ant와 Maven (그리고 다른 많은 툴)이 선언적 문법을 사용하여 프로 시저를 설명하는 방식입니다. 나는 목에 통통 한 고통 때문에 그것을 권하지 않습니다. 파이썬을 사용하는 것이 좋습니다.

또는 딥 엔드에서 벗어나 자신 만의 구문을 고안하고 자체 파서를 작성할 수 있습니다.

+0

좋은 제안이지만 필자는 여전히 효과적인 구문이나 형식에 대한 제안을 찾고 있습니다. 절차 적 또는 선언적인가? 커서를 처리하는 가장 좋은 방법은 무엇입니까? 기타 –

+0

이 두 지점에 응답하도록 편집되었습니다. 선언적. SQL 커서 루프는 핵심 클래스에 있습니다. –

0

"컴파일"할 때 SQL 또는 데이터 저장소에 필요한 모든 쿼리 언어를 생성하는 언어를 만들어 보지 않겠습니까?

기본적으로 지속성 계층에 대한 추상화를 만듭니다.

+0

서버 아키텍처는 가능한 여러 데이터 저장소 구현을 허용합니다. 가장 간단한 것 중 하나는 간단한 메모리 내 테이블이므로, 필자의 데이터 저장소에 필요한 쿼리 언어는 파이썬이다. –

0

당신은 파이썬에 대해 언급했습니다. 왜 파이썬을 사용하지 않습니까? 누군가 DSL에 표현식을 "입력"할 수 있다면, Python으로 타이핑 할 수 있습니다.

표현의 구조에 대한 규칙이 필요하지만 새로운 것을 구현하는 것보다 훨씬 쉽습니다.

+0

나는 이미 말했습니다 : 아무도 런타임에 임의 코드를 다운로드하고 실행하는 서버를 돌리고 싶어하지 않을 것입니다. 그리고 파이썬이 악의적 인 일을하지 않도록 철저히 검사 할 수있는 파서는 어쨌든 적절한 DSL을 작성하는 것만 큼 복잡 할 수 있습니다. –

+0

하지만 관리 할 수있는 보안 문제입니다. 예를 들어, DBA는 런타임에 임의의 코드를 다운로드 할 수 있습니다. 이 과정이 얼마나 희귀한지 생각해 보면, 일을 신뢰할 수있는 사람이 그 일을 할 수없는 이유는 없습니다. –

+0

요점은 각 서버 관리자가 수동으로 조작 할 필요가 없다는 것입니다. 이 방식으로 쿼리/필터링 할 수있는 DSL이 필요하지만 서버 관리자는 개입이나 감독없이 업데이트 될 수 있다고 믿을 수 있습니다. –

0

아무도 런타임에 임의 코드를 다운로드하고 실행하는 서버를 설치하려고하지 않는다고 말했습니다. 그러나 이것이 바로 DSL이 할 일이며 (결국) 차이가별로 없을 것입니다. 당신이 데이터에 대해 매우 특정한 것을하지 않는 한, DSL이 당신에게 그렇게 많은 돈을 사 줄 것 같지 않고 이미 SQL에 정통한 사용자들을 좌절시킬 것입니다. 당신이 수행 할 작업의 크기를 과소 평가하지 마십시오.

질문에 대답하려면 언어에 대한 문법, 텍스트를 구문 분석하고 트리를 걷거나 코드를 작성하거나 작성한 API를 호출해야합니다 (내 의견 여전히 일부 코드를 제공해야 함).

그물에서 참조 할 수있는 수학적 표현을위한 문법에 관한 교육용 텍스트가 많이 있습니다. 이는 상당히 간단합니다.ANTLR 또는 Yacc와 같은 파서 생성기 도구를 사용하여 파서를 생성하거나 Lisp/Scheme과 같은 언어를 사용하고 두 언어를 결합 할 수 있습니다. 합리적인 SQL 문법을 찾는 것은 쉽지 않습니다. 하지만 구글 'BNF SQL'과 당신이 무엇을 생각해 보라.

행운을 빈다.

+0

예, '임의의'코드를 다운로드하지만,이 DSL로 표현하면 많은 것을 할 수 없습니다. 임의의 파이썬 코드와 임의의 필터 표현식 (또는 이와 유사한 것)의 차이점이 있습니다. –

1

여기서 좀 더 자세한 정보가 필요하다고 생각합니다. 다음 중 하나라도 잘못된 가정에 근거한 것이 있으면 알려주십시오.

우선, 사용자가 지적했듯이 임의의 테이블에서 행을 선택하기위한 DSL이 이미 존재합니다.이를 "SQL"이라고합니다. SQL을 재발견하고 싶지 않으므로 고정 된 형식의 단일 테이블에서만 쿼리하면된다고 가정합니다.

이 경우에는 DSL을 구현할 필요가 없을 것입니다 (분명히 한 가지 방법이지만). 객체 오리엔테이션에 익숙하다면 Filter 객체를 만드는 것이 더 쉬울 수도 있습니다.

특히, 하나 이상의 SelectionCriterion 개체를 보유하는 "필터"컬렉션입니다. 이들을 구현하여 선택 유형을 나타내는 하나 이상의 기본 클래스 (Range, LessThan, ExactMatch, Like 등)에서 상속 할 수 있습니다. 이러한 기본 클래스가 마련되면 해당 열에 적합한 상속 된 상속 된 버전을 생성 할 수 있습니다 . 마지막으로, 지원하고자하는 쿼리의 복잡성에 따라 AND 및 OR을 처리하기위한 일종의 연결 접착제를 구현하고 다양한 기준 사이의 연결을 구현하려고합니다.

기분이 좋으면 간단한 GUI를 만들어 컬렉션을로드 할 수 있습니다. Excel에서 필터링을 모델로 보았습니다. 다른 것을 염두에 두지 않았다면 말입니다.

마지막으로,이 Collection의 내용을 해당 SQL로 변환하고이를 데이터베이스로 전달하는 것은 간단합니다.

그러나 단순한 경우 사용자가 SQL을 이해하면 WHERE 절의 내용을 입력하고 프로그래밍 방식으로 나머지 쿼리를 빌드하도록 요청할 수 있습니다. 보안 관점에서 코드가 선택된 열과 FROM 절을 제어 할 수 있고 데이터베이스 사용 권한이 올바르게 설정되어 있고 사용자로부터 들어오는 문자열에 대해 온 전성 검사를 수행하면 비교적 안전한 옵션이됩니다.

+0

대부분 소리가 나지만 여전히 필터 컬렉션을 지정하는 방법이 필요합니다. 목표는 업데이트 된 함수를 지정하고 클러스터의 모든 서버로 전파 할 수 있다는 것입니다. –

0

정말 SQL처럼 들리지만 간단하게 유지하려면 SQLite를 사용해 보는 것이 좋습니다.

1

가 나는 DSL을 원한다 "아무도 다운로드 및 실행시에 임의의 파이썬 코드를 실행하는 서버를 설치하려는 것 없다", "도메인 특정 언어를 구현하고"그러나 나는 파이썬을 원하지 않는다 그 DSL이 될 수 있습니다. 괜찮아. 이 DSL은 어떻게 실행합니까? 어떤 런타임 이면 Python이 아닌가?

파이썬 인터프리터를 임베드하는 C 프로그램이 있다면 어떻게 될까요? 그게 받아 들일 수 있니?

그리고 - 파이썬이 허용되는 런타임이 아니면 - 왜 파이썬 태그를 가지고 있습니까?

+0

파이썬에서 인터프리터를 작성하여 DSL을 실행할 것이다. 그것이 파이썬 태그가있는 이유입니다. 이 경우 DSL을 사용하는 전체적인 요점은 그것에 쓰여진 코드가 샌드 박스에서 벗어나 시스템 전체에 영향을 미치지 않는다는 것입니다. –

0

DSL이 아닌 문법을 만들고 싶습니다. ANTLR을 살펴보면 텍스트를 해석하고 특정 명령으로 해석 할 수있는 특정 파서를 만들 수 있습니다. ANTLR은 Python, SQL, Java, C++, C, C# 등을위한 라이브러리를 제공합니다.

또한, 여기에 파이썬으로 해석 될 수있는 DSL을 구축 C#을

+0

이것은 단지 문법 그 이상입니다. 구문 분석 만하지 말고 실행하여 완전한 DSL로 만들어야합니다. '계산 엔진'의 예제에는 파서에 임베드 된 실행 코드 만 있습니다. –

0

문맥 자유 문법은 일반적으로 구조와 같은 트리를 가지며 기능적 프로그램 역시 구조와 같은 트리 구조를 가지고 있습니다. 나는 다음과 같은 것이 당신의 모든 문제를 해결할 것이라고 주장하지 않지만, 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. 파이썬에서는 그렇게하기가 어렵지만, 리스프에서는 쉽습니다. 어디에서 lips와 같은 형식으로 평가할 함수 목록이 있습니까? 예 : where=(operator.add, (operator.getitem, row, v1), 2) 또는 where=(operator.mul, (operator.add, (opreator.getitem, row, v2), 2), 3).

이렇게하면 where 기능이 ALLOWED_FUNCS 또는 float, int, str과 같은 상수로만 구성되도록 apply_lisp 함수를 작성할 수 있습니다.

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의 열 번째 규칙 : 오 소년 우리는에 실행 한 모든 충분히 복잡한 C 나 포트란 프로그램은 커먼 리스프의 절반의 임시 비공식적으로 지정 버그 쟁이 느린 구현이 포함되어 있습니다.