[2010-8-24]

  1. 在评分式查询中,每篇文章被分解成若干部分,例如标题、摘要、作者和正文等;而查询则同样由若干个关键字组成。给出查询q后,对每篇文章都进行评分,分数越高则认为相关度越大,于是排名就越靠前。而在每篇文章评分过程中,则是对每个部分都独立进行评分,每个部分使用特有的匹配方式(最直接的就是简单字符串匹配)对查询q的每个关键字进行匹配,然后给出得分;各个部分计算出来的得分通过带权求和的方式计算出文章最后的得分。这个带权求和的过程,每个文章部分的权值通过样本训练的方式计算得出。

  2. 在上述的评分查询过程中,还可以加入关键字频率这一概念来优化查询结果的关联度。一般来说,对于同一个关键字,如果它一篇文章中出现的次数越多,则认为它的关联度越高,但这不是必然的。可以使用一个权值来表达关联度,这个权值会影响最后的评分,而最简单的方式就是直接使用关键字频率作为这个权值。但正如之前所说,文章的关键字频率并不绝对与其相关度成正比,例如查询q中包含"watch movie",而这两个关键字在文章d1和d2中的出现次数如下:

        d1  d2

  "watch"  30    15

  "movie"    0  10 

那是否就可以认为文章d1关于这个查询的相关度比d2大呢?很明显不可以,因为在查询的关键字中"movie"更能影响相关度,而"watch“则是一个普遍使用的关键字,出现在很多文章中,包括完全不相关的。但是我们也不可能为词库中所有的关键字都给差一个权值,因为权值是与查询有关的,我们不可能预测无限可能的查询。通过引入另一个概念,或许可以缓和这个问题的影响,那就是关键字的集合频率——以所有的文章作为一个集合(这里的所有可以根据实际情况定制),关键字在这个集合中出现的次数。通过引入这个概念,扩展上述例子,假设集合c是包括文章d1,d2,d3,...,dn。而两个关键字的集合频率如下:

             cf

  "watch"  13000

  "movie"  1000

从上述的例子数据可以看出,对于这个查询,检索系统应该“认为”在文章中,"movie"比"watch”具有更高的权值。这样权值就与关键字的集合频率成反比,看来问题已经解决了,但其实还有一个更加隐含的问题。假如集合c中包括了一部分专门讨论电影的文章(比如20%)。那么情况可能就会不一样,两个关键字的集合频率可能会变成这样:

         cf

  "watch"  13000

  "movie"  12400

马上,检索过程又会出现最初的问题:对于一篇只含"watch"而不含"movie“的文章d1,由于两个关键字的集合词频相当,于是它们具有相当的权值,于是d1的相关度就比d2还高了。出现这个情况的深层原因是,对于关键字的相关度参考量(集合频率)是在包含所有文章的集合层面上的统计,"watch"分布在集合的大部分文章中,而"movie"这分布在一部分的文章中,而评分过程应该关注后者(一部分文章),但目前的相关度参考量无法实现这一点,因此,需要引入的应该是一个局部文章集合层面上的统计量——文章频率,定义为:在一个集合中,包含关键字的文章数量。参考一下数据:  

          df

  "watch"  2600

  "movie"    540

通过引入文章频率,评分过程可以认为,具有越低的文章频率的关键字,具有更高的权值,这样一来,只含"watch"的d1比起含有"movie"的d2,其相关度评分要低很多,问题就这样解决了! 

  3. 写个遍历子目录的程序都写得我好狼狈,以前用.NET哗啦哗啦地就写完了,用WINDOWS API就是什么小事情都会变成大事情,看来我在WINDOWS API方面还很不适应啊。以后还可能要用LINUX的API,我晕。!

  在WINDOWS API中有个FindFirstData(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData)函数可以在当前工作目录下开始遍历子内容,包括目录和文件。第一个参数用于决定寻找怎样名称的子文件或子目录,使用_T("*.*")就可以遍历所有目录,包括隐藏的"."和"..",而这两个隐藏目录无论在哪一级目录中都会存在,因此在做递归遍历的时候(DFS)如果不跳过这两个隐藏目录,就会嵌入无穷递归。第二个参数就是用于保存遍历过程中当前的文件内容,该结构定义如下:

代码
typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
TCHAR cFileName[MAX_PATH];
TCHAR cAlternateFileName[
14];
} WIN32_FIND_DATA,
*PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;

在递归遍历功能中,需要用到cFileName(局部名称)和dwFileAttributes,通过if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)来判断当前文件是否目录。这个函数并没有通过参数来指定在哪个目录中遍历,原因是它默认在当前工作目录中遍历,因此在递归遍历的时候要在递归调用前,先调用SetCurrentDirectory函数设置当前的工作目录为即将要遍历的目录,而在遍历完成后,又要设置回原来的工作目录,因此也需要先调用GetCurrentDirectory函数做备份。FindFirstData函数会返回一个HANDLE,在继续遍历之前应该先检查该Handle是否合法,当参数中指定的要遍历的文件格式不存在时,就会返回非法句柄,并设置GetLastError值为2。



  在每个目录中,一旦调用了FindFirstData函数,接下来要继续遍历,就需要调用FindNextData函数,参数基本上都一样,只是这个函数用于移动遍历的游标,并且返回BOOL值指示是否还有下一个文件可以继续遍历。最后调用FindClose函数把寻找句柄关闭。

  整个程序代码如下:

代码
void EnumFolder()
{
WIN32_FIND_DATA data;
WCHAR
*pName = NULL;

HANDLE hFind
= ::FindFirstFile(L"*.*",&data);
WCHAR subFileFullPath[
260] , currentDir[260];
if(hFind != INVALID_HANDLE_VALUE)
{
do
{
wcout
<<"File Name:"<<data.cFileName;
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
cout
<<" is a dir, go deeper..."<<endl;
if(lstrcmp(data.cFileName,_T(".")) != 0 && lstrcmp(data.cFileName,_T("..")) != 0)
{
::GetFullPathName(data.cFileName,
260,subFileFullPath,NULL);
::GetCurrentDirectory(
260,currentDir);
::SetCurrentDirectory(subFileFullPath);
EnumFolder();
::SetCurrentDirectory(currentDir);
}
}
else
{
cout
<<" is a file"<<endl;
}
}
while(::FindNextFile(hFind,&data));
::FindClose(hFind);
}
}

   4. 找到了一篇简述各种WINDOWS API中字符串宏的文章:http://blog.csdn.net/doubaijun/archive/2008/11/14/3297104.aspx

posted @ 2010-08-24 20:12  DOF_KL  阅读(198)  评论(0编辑  收藏  举报