CaiHuajiang
2009-11-25 10:06 阅读 265

lucene设置Field为un_tokenized时怎么匹配,答对者送wave了

有一段文本,有名称mc与内容nr两段。nr好说,分词不储存。
mc格式为“中国>>上海>>普陀”这种形式,为了保证其精确性,在检索时不会被拆分,所以不设置分词,设置Field.Index.UN_TOKENIZED。
那么问题是,在检索名称时,由于mc被认为是一个最小的单位,那么该怎么查询。
这里不知道谁有个好的思路?

其实我想问的问题是如何在搜索引擎中使用精确搜索。lucene中将文本进行分词,再来进行匹配。但是有一些内容(如上面的mc)就要求十分准确,甚至不管其中有没有特殊符号或者用户输入的关键字那不能识别出来等,都需要查询出来。
所以在设置时是将Field.Index为UN_TOKENIZED,那么在存储时就会将这段文本做为一个term,如上文中“中国>>上海>>普陀”,这个时候除了使用"中国>>上海>>普陀"本身,不知道有其它办法进行匹配。如用户在只输出“上海”的情形下,怎么找到这段文本。
[color=red]
大家谁有思路都可以给个参考啊,最后还有4个wave邀请送给大家! :D :D :D [/color]

[b]问题补充:[/b]
你说的有点意思了。但是回到了最开始的问题了。
你推荐了一个前缀匹配查询,当然,我一开始的设想是通配符查询。
但是存在同样的一个问题就是,如果存在以下两个词条
中国>>上海>>普陀
中国>>上海上>>普陀
那么,当用户输入“上海”时,希望能够匹配“中国>>上海>>普陀”
而不是那个“中国>>上海上>>普陀”的地方
[b]问题补充:[/b]
关于分词,你可能误解我的意思,我当然不担心保存在索引中的数据会发生变化,担心的是,分词可能会导致查询的准确性不能达到100%,对于有些文本不会追求准确性的,但总有些要求很精准的。尤其是一些目录结构的,用户可能就是挑中能记忆的名称输入,但是系统总得查询出来与之相关的所有内容。
当然,如你所说,分词的效果取决于分析器的效果。我知道分词口号就是10%的设置能应用于90%的情况。这里的要求是不是有点太苛求了。
至于你所说的HitCollector,还没有看过,我先看看,再试下。
[b]问题补充:[/b]
哦,谢谢了,我先试试。
我要遵守承诺,发一个wave,你把你的邮箱留下吧。
帖子不关,等看看还有没有人来指导下。集思广益,看看有没有其它思路。
如果还有什么问题,我可能会直接发站内信麻烦你了。
[b]问题补充:[/b]
[quote]地区间用空格,然后用SimpleAnalyzer去解析, [/quote]
本来想用你的思路来试下,没想到遇到的第一个问题就是:
我现在的是
[code="java"]Analyzer analyzer = new PaodingAnalyzer();
IndexWriter indexWriter = new IndexWriter(indexFile, analyzer, true);[/code]
怎么能同时用SimpleAnalyzer呢
[b]问题补充:[/b]
SimpleAnalyzer的效果肯定是要不得的,因为在全文分词是会依据空格分成一句一句的。
而且在分词后,还是会出现匹配上问题
[b]问题补充:[/b]
嗯,经过测试,我确定HitCollector可以满足需求。
其实在昨天,我有了一个更简单的方案。因为数据全部存储在oracle中,因此可以使用oracle Text。
当然,oracle的分词效果好像并不好,不过对现有代码改动之类都比较小,并且也能够满足需求。
要谢谢两位的帮忙。
luckaway请留下您的邮箱。
[b]问题补充:[/b]
[quote]硬编码在Analyzer里 [/quote]
这样到是可以将中国>>上海>>普陀分得更加的准确。
其实,可能我没有说清。关键关不是在分词的准确上,而是要求查询匹配得准确要求非常高。你不可能指望那些可能念都不念不通的话会分成一个term的。
layer555说的HitCollector,就是实现这个目的,因为我希望那部分内容是进行不分词索引的,并且还要求用一种特别的规律进行查询出来。
[b]问题补充:[/b]
嗯,好的。
如果搜索上有问题,还会向你请教的。

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

9条回答 默认 最新

  • 已采纳
    layer555 layer555 2009-11-25 16:33

    HitCollector很简单,它提供了一个collect方法,用于收集搜索结果,在这个时候你可以通过docId访问到数据的mc字段,然后最简单的办法就是你通过字符串split一下,然后逐个匹配,这样肯定是最精确的;至于怎么匹配合理,看情况做就是了。PrefixQuery的内部实现也不过就是通过字符串匹配做的,只不过与Lucene贴合的紧密,更高效而已。至于调用的话Searcher中有search方法是包含HitCollector的,试一下就知道了。

    点赞 评论 复制链接分享
  • layer555 layer555 2009-11-25 15:38

    呵呵 总算知道你是什么意思了,跟我刚做过的功能一样。相当搜索树形结构上的某一点下的所有子节点。而且节点的路径也遵循树状结构;而且其实搜索的key是固定的,不是由用户输入的。那就考虑采用PrefixQuery试试看,在数据库中根据ID查找到全路径,然后将全路径作为PrefixQuery的关键字做查询,而mc字段也不用分词;其实做的就是一个前缀匹配查询。

    点赞 评论 复制链接分享
  • layer555 layer555 2009-11-25 16:03

    你的搜索条件到底由用户输入的还是后台自行获取的? 如果搜索条件确实保存在数据库中在后台获取的话,OK,那么用前缀搜索完全可以满足; 如果你要求是用户输入的,那么就肯定要分词了,而且至于你提到的上海会不会搜到上海上我觉得就取决于你的分析器的效果了; 如果你只是单纯的想保留特殊符号,我觉得分词对它没有影响;分词的话只是在搜索的时候无法搜索到这些符号,但不会影响保存的数据,保存在索引中的还是完整的; 更进一步的,你如果想把每两个”>>“的文字作为一个基本单位搜索的话,我推荐你另外一个方法:采用HitCollector,在收集搜索结果的时候自行匹配,自己来制定匹配规则,这样会稍微慢一点,但肯定满足你的需求。

    点赞 评论 复制链接分享
  • cqllang cqllang 2009-11-25 21:41

    :? 想知道你说的wave是什么东东。。 :oops:

    点赞 评论 复制链接分享
  • badonly badonly 2009-11-26 12:30

    地区间用空格,然后用SimpleAnalyzer去解析,

    下面是我的测试代码

    CharTokenizer是SimpleAnalyzer里分词器

    [code="java"]
    public static void main(String args[]) {
    try {
    CharTokenizer charTokenizer = new LetterTokenizer(new StringReader("中国 浙江 杭州"));
    Token token = charTokenizer.next();
    while (token != null) {
    System.out.println(token);
    token = charTokenizer.next();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    [/code]
    输出结果
    (中国,0,2)
    (浙江,3,5)
    (杭州,6,8)

    分词正确

    点赞 评论 复制链接分享
  • badonly badonly 2009-11-26 12:37

    [quote]
    HitCollector很简单,它提供了一个collect方法,用于收集搜索结果,在这个时候你可以通过docId访问到数据的mc字段,然后最简单的办法就是你通过字符串split一下,然后逐个匹配,这样肯定是最精确的;至于怎么匹配合理,看情况做就是了。PrefixQuery的内部实现也不过就是通过字符串匹配做的,只不过与Lucene贴合的紧密,更高效而已。至于调用的话Searcher中有search方法是包含 HitCollector的,试一下就知道了。
    [/quote]

    这个方法有失搜索引擎的本质!不推荐

    点赞 评论 复制链接分享
  • layer555 layer555 2009-11-26 14:45

    [quote]这个方法有失搜索引擎的本质!不推荐[/quote]
    问题在于这个问题已经不是分词所能够解决的问题,就算分词正确,却达不到精确匹配的目的。他的需求很麻烦,你可以跟他多确认几次需求就知道了。

    点赞 评论 复制链接分享
  • badonly badonly 2009-11-26 15:35

    不好意思,没考虑充分。

    要不自己在PaodingAnalyzer基础上在封装一层。或者直接修改PaodingAnalyzer

    [quote]
    public class TestStandardAnalyzer extends StandardAnalyzer {
    @Override
    public TokenStream tokenStream(String fieldName, Reader reader) {
    if (fieldName.equals("mc"))
    return new LetterTokenizer(reader);
    else
    return super.tokenStream(fieldName, reader);
    }
    }
    [/quote]

    硬编码在Analyzer里

    点赞 评论 复制链接分享
  • badonly badonly 2009-11-26 15:42

    google wave我已经有了,上次朋友已经邀请我的!

    luckalway@gmail.com

    搜索相关的以后可以讨论下!
    呵呵

    点赞 评论 复制链接分享

相关推荐