[Hyper Estraier] _estraiernative.Database.get_docの第2引数には、オプションを指定する。
環境
この記事の内容は、Ubuntu Linux 6.10, Python 2.4.4, Hyper Estraier 1.4.10, qdbm 1.8.75, libiconv 1.11, estraiernative 0.2で確認しました(Hyper Estraierとqdbm, libiconv, estraiernativeは、パッケージ管理システムからではなく、ソースコードからmake installしました)。
estraiernativeにおける検索方法
estraiernativeは、Hyper EstraierのPythonのバインディングです。現時点では開発中でドキュメントもありませんが、検索の仕方は、examples/search.pyのソースコード(以下)を読めば、おおよそ理解できます。
# -*- coding: utf-8 -*- ## $Id: search.py,v 1.1 2007/04/15 05:52:47 yosida Exp $ # try : from _estraiernative import * except ImportError : import sys; sys.path.insert(0, '../') from _estraiernative import * # create the database object db = Database() # open the database if not db.open("casket", Database.DBREADER) : print "error: %s\n", db.err_msg(db.error) raise SystemExit(1) # create a search condition object cond = Condition() # set the search phrase to the search condition object cond.set_phrase("rainbow AND lullaby") # get the result of search result = db.search(cond) # for each document in the result dnum = result.doc_num() for i in range(0, dnum) : # retrieve the document object doc = db.get_doc(result.get_doc_id(i), 0) if doc is None : continue # display attributes uri = doc.attr("@uri") if uri : print "URI: %s", uri title = doc.attr("@title") if title : print "Title: %s", title # display the body text for text in doc.texts() : print "%s", text # close the database if not db.close() : print "error: %s", db.err_msg(db.error)
この中で、おそらく問題となるのは、次の行です。
doc = db.get_doc(result.get_doc_id(i), 0)
ここでは、_estraiernative.Database.get_docメソッドの第2引数に0を指定していますが、これはなんなのでしょうか? これを調べるため、estraiernative.cを読んでみます。get_docメソッドは、以下のようにして設定されていました。
{"get_doc", _est_db_get_doc, METH_VARARGS, NULL},
どうやら、get_docメソッドを呼び出すと、_est_db_get_doc関数を呼び出すようです。では、_est_db_get_doc関数を除いてみます(以下)。
static PyObject* _est_db_get_doc(PyObject *self, PyObject *args) { PyESTDB *pdb = (PyESTDB*)self; int id, opts; PyESTDOC *pdoc; ESTDOC *doc; if (!PyArg_ParseTuple(args, "ii", &id, &opts)) return NULL; null_check(pdb->db, "db is closed"); doc = est_mtdb_get_doc(pdb->db, id, opts); if (doc) { pdoc = PyObject_New(PyESTDOC, &PyESTDOC_Type); pdoc->doc = doc; return (PyObject*)pdoc; } else { Py_INCREF(Py_None); pdb->ecode = est_mtdb_error(pdb->db); return Py_None; } }
get_docメソッドに与えられた引数は、
if (!PyArg_ParseTuple(args, "ii", &id, &opts))
の行により、id変数とopts変数に格納されるのが分かります。では、opts変数を使っている場所を調べてみます。それは、以下の箇所です。
doc = est_mtdb_get_doc(pdb->db, id, opts);
est_mtdb_get_doc関数は、Hyper Estraierの関数です。そこで、Hyper Estraierのソースコードをgrep して、est_mtdb_get_doc関数の所在を調べます。すると、est_mtdb_get_doc関数はestmtdb.cにあり、以下のようであることが分かりました。
/* Retrieve a document in a database. */ ESTDOC *est_mtdb_get_doc(ESTMTDB *db, int id, int options){ ESTDOC *rv; assert(db && id > 0); if(!est_mtdb_lock(db)) return NULL; rv = est_db_get_doc(db->db, id, options); est_mtdb_unlock(db); return rv; }
与えたoptionsは、さらにest_db_get_doc関数に渡っています。est_db_get_doc関数は、estraier.cにありました。
/* Retrieve a document in a database. */ ESTDOC *est_db_get_doc(ESTDB *db, int id, int options){ ESTDOC *doc; const char *cbuf; char *vbuf, numbuf[ESTNUMBUFSIZ]; int i, csiz, vsiz, num; assert(db && id > 0); if(id >= ESTPDOCIDMIN){ if((num = id - ESTPDOCIDMIN) >= CB_LISTNUM(db->pdocs)){ est_set_ecode(&(db->ecode), ESTENOITEM, __LINE__); return NULL; } if((vbuf = cbreadfile(CB_LISTVAL(db->pdocs, num), NULL)) != NULL){ doc = est_doc_new_from_draft(vbuf); free(vbuf); } else { doc = est_doc_new(); } doc->id = id; sprintf(numbuf, "%d", id); est_doc_add_attr(doc, ESTDATTRID, numbuf); if(!est_doc_attr(doc, ESTDATTRURI)) est_doc_add_attr(doc, ESTDATTRURI, CB_LISTVAL(db->pdocs, num)); return doc; } cbuf = NULL; if(options & ESTGDNOATTR){ if(crvsiz(db->attrdb, (char *)&id, sizeof(int)) == -1){ if(dpecode == DP_ENOITEM){ est_set_ecode(&(db->ecode), ESTENOITEM, __LINE__); return NULL; } else { est_set_ecode(&(db->ecode), ESTEDB, __LINE__); db->fatal = TRUE; return NULL; } } vbuf = NULL; } else if((cbuf = cbmapget(db->attrcc, (char *)&id, sizeof(int), &csiz)) != NULL){ cbmapmove(db->attrcc, (char *)&id, sizeof(int), FALSE); vbuf = NULL; } else if(!(vbuf = est_crget(db->attrdb, db->zmode, id, &vsiz))){ if(dpecode == DP_ENOITEM){ est_set_ecode(&(db->ecode), ESTENOITEM, __LINE__); return NULL; } else { est_set_ecode(&(db->ecode), ESTEDB, __LINE__); db->fatal = TRUE; return NULL; } } doc = est_doc_new(); doc->id = id; if(cbuf){ doc->attrs = cbmapload(cbuf, csiz); } else if(vbuf){ doc->attrs = cbmapload(vbuf, vsiz); if(db->acmnum > 0) cbmapput(db->attrcc, (char *)&id, sizeof(int), vbuf, vsiz, TRUE); free(vbuf); if(cbmaprnum(db->attrcc) > db->acmnum){ num = cbmaprnum(db->attrcc) * 0.1 + 1; cbmapiterinit(db->attrcc); for(i = 0; i < num && (cbuf = cbmapiternext(db->attrcc, NULL)) != NULL; i++){ cbmapout(db->attrcc, cbuf, sizeof(int)); } } } else { doc->attrs = NULL; } if(!(options & ESTGDNOTEXT)){ if((cbuf = cbmapget(db->textcc, (char *)&id, sizeof(int), &csiz)) != NULL){ cbmapmove(db->textcc, (char *)&id, sizeof(int), FALSE); doc->dtexts = cblistload(cbuf, csiz); } else { if(!(vbuf = est_crget(db->textdb, db->zmode, id, &vsiz))){ est_set_ecode(&(db->ecode), ESTEDB, __LINE__); db->fatal = TRUE; est_doc_delete(doc); return NULL; } doc->dtexts = cblistload(vbuf, vsiz); if(db->tcmnum > 0) cbmapput(db->textcc, (char *)&id, sizeof(int), vbuf, vsiz, TRUE); free(vbuf); if(cbmaprnum(db->textcc) > db->tcmnum){ num = cbmaprnum(db->textcc) * 0.1 + 1; cbmapiterinit(db->textcc); for(i = 0; i < num &&(cbuf = cbmapiternext(db->textcc, NULL)) != NULL; i++){ cbmapout(db->textcc, cbuf, sizeof(int)); } } } } if(!(options & ESTGDNOKWD)) doc->kwords = est_db_get_keywords(db, id); return doc; }
この関数の中で、options引数は、以下の定数と組み合わせて使用されています。
- ESTGDNOATTR
- ESTGDNOTEXT
- ESTGDNOKWD
これは何を意味するのでしょうか? 答えは、Hyper Estraierのプログラミングガイドにありました。
ESTDOC *est_db_get_doc(ESTDB *db, int id, int options);
`db' はデータベースオブジェクトを指定します。`id' は登録文書のID番号を指定します。`options' はオプションを指定します。`ESTGDNOATTR' は属性を取得しないことを指示し、`ESTGDNOTEXT' は本文を取得しないことを指示し、`ESTGDNOKWD' はキーワードを取得しないことを指示します。オプションはビット和で同時に指定できます。戻り値は文書オブジェクトか、エラーなら `NULL' です。戻り値のオブジェクトは `est_doc_new' で生成されているので、不要になったら `est_doc_delete' で破棄してください。
これらの定数をPythonから使用できるようにするため、estraiernativeでは、以下のように定数を定義しています(どうやら、ESTGDNOKWDは定義されていないようです)。
PyMODINIT_FUNC init_estraiernative(void) { : define_const(d, "GDNOATTR", ESTGDNOATTR); define_const(d, "GDNOTEXT", ESTGDNOTEXT); :
これにより、Python内ではこれらの定数を以下のようにして参照できます(もちろん、本来の使いかたは、_estraiernative.Database.get_docメソッドの第2引数に使用することです)。
import _estraiernative
_estraiernative.Database.GDNOATTR | _estraiernative.Database.GDNOTEXT