Namazu-devel-ja(旧)


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

BER圧縮のデータの読み込みについて



はじめまして、図書館情報大学4年の高橋というものです。
Namazuを焼こうと、下ごしらえをいろいろとやっています。

さて、 MLのusers-jaの03312、フレーズ検索のHASH値への変換方法の
スレッドで話題になった件で気になった点をあげます。

こちらのバグに気づき、藤原さんが書かれた最新版(13pre7)の
ソースを拝見したのですが、まだうまくいってないと思います。
参考のため、関数を載せさせていただきます。

まず、nmz_get_unpckw()で、NMZ.iの対象語の一つ目のデータ
(表記について問題になったもの)をnに代入していますが、
この時点のnは、データ長、つまりバイトですよね。
それをmaxhit * 2と比較するのはおかしいかと思います。

具体的に、駄目な例ですが、文書IDが128、スコアが128の場合、
これ一つだけだと、nは4(byte)が入りますね。
これが500個あるとすると、
(差分を考慮すると、文書IDは2個目だったら実IDは256、という意味です)
n = 4(byte) * 500 = 2000(byte) になります。
しかし、実際のデータの数は500ですので、
hit = (bersize < maxhit * 2 ? bersize : maxhit * 2);
の式は、hitに maxhit * 2 がはいってしまします。
(maxhit ってデフォルトで1000ですよね?)

よって、この式を評価する前に、nに文書数を入れておく必要があります。
というか、nが場所によって、バイト数になったり、ヒット文書数*2になったり
ヒット文書数になったりしているので、別な変数を用意したほうが
よいのではないかと思います。
これが1点。

もうひとつが、
 idf = log((double)document_number / (n/2)) / log(2);
	nmz_debug_printf("idf: %f (N:%d, n:%d)\n", idf, document_number, n/2);
ここでのnは、やはりバイト数が入っているままなのですが、これだと
やはりいけないと思います。
ここで用いたい「n」は「ヒット文書数 * 2」なので。


それで、上記の解決策ですが、nmz_get_unpackw()で
バイト数を求めた後、直後に、buf = malloc(n * sizeof(int));
をすれば大丈夫だと思います。
しかし!!余分にメモリを確保する(可能性がある)のはいなめないのですが。。。

皆様のご意見をお待ちしております。
長文になって申し訳ございません。


P.S.

「BER圧縮」ってベル圧縮と読んでいいのでしょうか?


図書館情報大学4年

 高橋英幸 <k176@xxxxxxxxxx>




NmzResult 
nmz_get_hlist(int index)
{
    int n, *buf, i;
    NmzResult hlist;
    double idf = 1.0;

    hlist.num  = 0;
    hlist.data = NULL;
    hlist.stat = SUCCESS;

    if (-1 == fseek(Nmz.i, nmz_getidxptr(Nmz.ii, index), 0)) {
	hlist.stat = ERR_FATAL;
	return hlist; /* error */
    }

    nmz_get_unpackw(Nmz.i, &n);

    if (nmz_is_tfidfmode() &&
	(nmz_get_querytokennum() > 1
	 /* 0th token is a phrase. */
	 || strchr(nmz_get_querytoken(0), '\t') != NULL)) 
    {
        idf = log((double)document_number / (n/2)) / log(2);
	nmz_debug_printf("idf: %f (N:%d, n:%d)\n", idf, document_number, n/2);
    }

    {
	int sum = 0;
	int hit;
	int maxhit = nmz_get_maxhit();
	int bersize = n;
	int totalsize;

	hit = (bersize < maxhit * 2 ? bersize : maxhit * 2);
	buf = malloc(hit * sizeof(int));
	if (buf == NULL) {
	    nmz_set_dyingmsg(nmz_msg("%s", strerror(errno)));
	    hlist.data = NULL;
	    hlist.stat = ERR_FATAL;
	    return hlist;
	}

	n = 0;
	totalsize = 0;
        while (totalsize < bersize) {
            totalsize += nmz_get_unpackw(Nmz.i, &buf[n]);
            n++;
            if (n > maxhit * 2) {
                hlist.stat = ERR_TOO_MUCH_HIT;
                free(buf);
                return hlist;
            }
        }
        n /= 2;

	nmz_malloc_hlist(&hlist, n);
	if (hlist.stat == ERR_FATAL) {
	    free(buf);
	    return hlist;
        }
	
	for (i = 0; i < n; i++) {
	    hlist.data[i].docid = *(buf + i * 2) + sum;
	    sum = hlist.data[i].docid;
	    hlist.data[i].score = *(buf + i * 2 + 1);
	    if (nmz_is_tfidfmode()) {
		hlist.data[i].score = (int)(hlist.data[i].score * idf) + 1;
	    }
	}
        hlist.num = n;
	free(buf);
        hlist = nmz_do_date_processing(hlist);
    } 
    return hlist;
}