2014-10-03 2 views
1

해시 테이블 조회를 위해 이동하기로 결정한 것처럼 빠르게 검색해야하는 레코드 테이블이 있습니다.다중 인덱스 해시 테이블 구현

이제는 여러 키를 기반으로 레코드를 조회해야한다는 문제가있었습니다.

예를 들어, 아래의 4 키는 모두 동일한 레코드를 가리켜 야합니다.

key1 -> a,b,c,d,e 
key2 -> a,b,d 
key3 -> a,b,e 
key4 -> c 

문제 # 1 이 패턴은 여러 개의 키가 지정된 데이터베이스 조회에 유사성을 보여 주었다. B- 트리 데이터 구조는 다중 해시 테이블 설계보다 사용하기에 최적일까요?

문제 # 2 특수한 트라이가 문제에 더 잘 맞는지 여부. 기본 구현에서는 모든 키 a + b + c + d + e를 검색 키로 요구합니다. + b + d를 조회해야한다면이 마스터 키를 사용하여 올려다 보면서 C & e를 건너 뛸 수 있습니다. 그렇다면이 아이디어가 효과가 있느냐, 이미 밖으로 나가고 있는가?

문제 # 3 또 다른 아이디어는 내 테이블에 물건을 삽입했는지, 아니면 병렬로 각 레코드에 인덱스가있는 다른 룩업 테이블을 구축했는지입니다. 그런 식으로 각 키에 대해 여러 개의 마스크를 사용할 수 있으며이 조회 테이블에서 일치하는 레코드를 검색 할 수 있습니다. CAM 테이블과 비슷한 것 같습니다. 그러나 전체 테이블을 스캔해야한다면 성능이 떨어질 수 있습니다. 해시 테이블 + 인덱싱 로직을 함께 사용하여 속도와 최적의 메모리 사용량을 제공 할 수 있습니까?

지금까지 부스트 멀티 인덱스, uthash, trie 등을 사용하여 4 가지 문제는 모두 해결했지만 아직까지는 성공하지 못한 디자인을 시도했습니다. 나는 멀티 인덱스를 향상시키는 것을 좋아했지만, 그것은 내가 사용할 수없는 문제의 자신의 몫을 가지고있다.

프로그래밍을 위해 C 언어를 사용하지만 디자인을 테스트하는 데 Java, PHP, Python과 같은 다른 언어도 사용할 수 있습니다.

이 문제를 해결하기위한 다른 아이디어는 크게 감사하겠습니다. 내가 달성하고자하는 솔루션의

의사 코드 :

/* Keys */ 
struct key1_s { 
int src; 
int dst; 
char name[10]; 
int t1; 
int t2; 
}; 

struct key2_s { 
int src; 
int dst; 
char name[10]; 
}; 

struct key3_s { 
int src; 
int dst; 
int t1; 
}; 


struct key4_s { 
int src; 
int dst; 
int t2; 
}; 


/* Record */ 
struct record_s { 
int src; 
int dst; 
char name[10]; 
int t1; 
int t2; 
int age; 
int sex; 
int mobile; 
} 

struct record_s record[2] = { 
{1, 2, "jack", 5, 6, 50, 1, 1234567890}, 
{3, 4, "john", 7, 8, 60, 2, 1122334455} 
}; 
table.insert(record[0]); 
table.insert(record[1]); 

/* search using key1 */ 
struct key1_s key1; 
key1.src = 1; 
key1.dst = 2; 
strncpy(key1.name, "jack", 10); 
key1.t1 = 5; 
key1.t2 = 6; 
table.find(key1); // should return pointer to record[0] 

/* search using key2 */ 
struct key2_s key2; 
key2.src = 1; 
key2.dst = 2; 
strncpy(key1.name, "jack", 10); 
table.find(key2); // should return pointer to record[0] 

/* search using key3 */ 
struct key3_s key3; 
key3.src = 1; 
key3.dst = 2; 
key3.t1 = 5; 
table.find(key3); // should return pointer to record[0] 

찾기()가 성공적으로 포인터를 돌려주는 경우, 나는 나이, 성별, 모바일과 같은 레코드의 필드를 업데이트하고 싶습니다.

+1

표기법으로 혼란을 SRY, 나는이 문제에 대한 BMI를 사용했던 일부 의사 코드 – Athif

답변

0

부스트 멀티 인덱스가 여기에 도움이됩니다.

composite_keys.cpp 예제에는 강력한 예제가 들어 있습니다. orderedhashed으로 대체하면 처리 할 대상을 얻을 수 있습니다 (또한 주요 구성에서 중복되는 경우가 더 많습니다).

성능 질문과 관련하여 명확한 대답은 없다고 생각합니다. 그것은 (항상) 사용 패턴에 달려 있습니다. 최적화에 소요되는 노력을 프로파일 링하고 균형을 유지해야합니다.

나는 편리하고 빠른 결과에 중점을 두었을 때 부스트 멀티 인덱스를 사용하는 것이 좋습니다. 이것이 BMI가 최적화되어 있지 않다는 것을 의미하는 것은 아닙니다 (나는 이것이 매우 최적화되어 있다고 생각합니다). 그러나/항상/사용 패턴에 의존합니다. (대량의 데이터를 대량으로 삽입 한 다음 읽는 응용 프로그램을 고려해 볼 때 이러한 응용 프로그램은 각 삽입시 모든 인덱스를 자동으로 업데이트하는 대신 명시 적으로 인덱스를 한 번만 작성하면 도움이 될 수 있습니다).

는 다음의 사용 사례와 몇 가지 문제가 Live On Coliru

using namespace boost::multi_index; 

/* A file record maintains some info on name and size as well 
* as a pointer to the directory it belongs (null meaning the root 
* directory.) 
*/ 

struct file_entry 
{ 
    file_entry(
    std::string name_,unsigned size_,bool is_dir_,const file_entry* dir_): 
    name(name_),size(size_),is_dir(is_dir_),dir(dir_) 
    {} 

    std::string  name; 
    unsigned   size; 
    bool    is_dir; 
    const file_entry* dir; 

    friend std::ostream& operator<<(std::ostream& os,const file_entry& f) 
    { 
     os << f.name << "\t" << f.size; 
     if (f.is_dir)os << "\t <dir>"; 
     return os; 
    } 
}; 

/* A file system is just a multi_index_container of entries with indices on 
* file and size (per directory). 
*/ 
struct dir_and_name_key:composite_key< 
    file_entry, 
    BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry*,dir), 
    BOOST_MULTI_INDEX_MEMBER(file_entry,std::string,name) 
>{}; 

struct dir_and_size_key:composite_key< 
    file_entry, 
    BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry* const,dir), 
    BOOST_MULTI_INDEX_MEMBER(file_entry,unsigned,size) 
>{}; 

typedef multi_index_container< 
    file_entry, 
    indexed_by< 
    hashed_unique<dir_and_name_key>, 
    hashed_non_unique<dir_and_size_key> 
    > 
> file_system; 

/* typedef's of the two indices of file_system */ 
typedef nth_index<file_system,0>::type file_system_by_name; 
typedef nth_index<file_system,1>::type file_system_by_size; 

/* We build a rudimentary file system simulation out of some global 
* info and a map of commands provided to the user. 
*/ 

static file_system fs;     /* the one and only file system */ 
static file_system_by_name& fs_by_name=fs;   /* name index to fs */ 
static file_system_by_size& fs_by_size=get<1>(fs); /* size index to fs */ 
static const file_entry* current_dir=0;   /* root directory */ 
+0

를 추가, 내가 무엇을 의미하는지 명확하게 볼 수 있지만 발견 : – Athif

+0

이 문제에 BMI를 사용했지만 문제를 해결하는 동안 몇 가지 문제가 발생했습니다. 내가 가지고있는 사용 패턴은 초기에 벌크 삽입이있을 것이며, 그 후에 고속으로 업데이트/삭제가있게 될 것입니다. 이것은 내가 쳤던 곳이다. 테이블에서 레코드를 업데이트해야 할 때마다 table.replace (key, newrecord)를 호출하면 실제로 이전 레코드가 삭제되고 새 레코드가 삽입됩니다. 나는 이것이 꽤 비싼 작업임을 알았다. 대신 포인터를 얻을 수 있다면 레코드를 업데이트 할 수 있기를 바랍니다. – Athif

+0

키 필드를 업데이트하지 않으면 색인을 업데이트 할 수 없습니다. 키 필드를 수정하지 않으면 참조를 통해 수정하는 것이 좋습니다. – sehe