whoosh使用笔记

1. whoosh安装

  pip install Whoosh

2. 添加索引

  第一步:生成schema

       第二步:根据schema生成index.index就是一个目录中的一堆文件
   (针对某个目录,调用一个已存在的索引名字的index.create_in方法,会清空已存在索引的内容!).若想清除索引,可以把目录中的索引文件删掉。若目录中仅有一个索引,可以删除整个目录,然后从新生成目录即可。
  第三步:根据index生成writer(调用index.writer())
  第四步:writer.add_document即可

  由于打开writer时会lock住索引文件,因此在某一时间,仅有一个线程或进程可打开一个writer.打开一个已被lock的writer会抛出LockError.whoosh提供了AsyncWriter和BufferWriter可以在lock状况下工作。
  对于某字段,可以索引与存储分开,使用stored_<fieldname>字段即可。 writer不commit, 或者cancel, 其他线程或进程不可再打开writer

3.  编辑和删除索引

  删除操作使用writer的以下三个方法
            delete_document(docnum)方法 (docnum是索引查询结果的每条结果记录的docnum属性)
            delete_by_term(field_name,termtext)方法 (特别适合删除ID,或KEYWORD字段)
            delete_by_query(query)
       删除一个index仅仅是把该document的docnum添加到一个deleted index列表中

  编辑即replace,可以使用上面的delete_*方法删除后,使用add_document添加。也可以使用update_document。使用该方法时,在schema里定义的字段,至少有一个字段是定义有unique属性的。whoosh使用该unique字段查找文档,然后删除之。

  

 1 from whoosh.fields import Schema, ID, TEXT
 2 
 3 schema = Schema(path = ID(unique=True), content=TEXT)
 4 ix = index.create_in("index")
 5 writer = ix.writer()
 6 writer.add_document(path=u"/a", content=u"The first document")
 7 writer.add_document(path=u"/b", content=u"The second document")
 8 writer.commit()
 9 
10 writer = ix.writer()
11 # Because "path" is marked as unique, calling update_document with path="/a"
12 # will delete any existing documents where the "path" field contains "/a".
13 writer.update_document(path=u"/a", content="Replacement for the first document")
14 writer.commit()

  其实unique字段和update_document就是delete和add的一种shortcut.

4. 查询索引       

  第一步:若索引已添加了,调用open_dir("dir of index")即可返回index,若出现exception则说明,还没有添加任何索引。

  第二步:通过调用index.searcher(),根据index生成searcher. searcher就是打开的一堆文件,用完一定要关闭。 searcher有很多获取索引信息的有用方法,
         比如lexicon(fieldname):得到某字段的全部分词。当然其中最重要的方法就是search方法。

  第三步: 生成查询对象, 有两种方式:

    直接构建query对象:
                类似于:myquery = And([Term("content", u"apple"), Term("content", "bear")])
    query language:
      就是解析查询的字符串后,生成一个query对象
      step1, 通过 parser=QueryParser("content",index.schema),先生成一个parser. 其中content是若不定义字段时,默认的查询字段。
      step2, 调用parser.parse(querystring),分析query,生成query对象

  第四步: 以query对象为参数调用searcher的search方法.得到查询result.
    默认的search方法的results最多仅返回10个匹配的文档。若想返回更多,就要使用limit参数查询了:
    results = searcher.search(query,limit=20). 若要得到全部的结果,可把limit=None.
    search_page(query,page)方法可已让你得到某page的结果,默认是一页10个hit,可以使用pagelen参数调整
    search_page(query,page,pagelen=20)
    Results对象表现的就像是list一样:可进行len(results), results[0], results[0:2]
    由于默认的results仅返回10条记录,所以results的scored_length()可能会小于索引中实际匹配的总条目数。

    而调用len(result),其实是运行了一个快速的非计分版本的查询,得到的是匹配的全部文档数。这个调用通常很快速,但是若是遇到一个很大的索引的话,会有明显的延迟。
    若要避免这种延迟,可以使用has_exact_length(), estimated_length(), and estimated_min_length() 去估算匹配的文档数目而不是使用len()
    len()返回的是全部的满足条件的文档数量,estimate_*返回的是预估的数量,若预估已确切,则是确切的数量.scored_length()返回的数值小于等于limit
            
    可以在search方法中设置terms=True,来记录:在terms查询中,哪个term匹配哪个document.然后通过results.matched_terms()调用,返回results中匹配了哪些term.
    在hit中调用matched_terms()返回,在hit中匹配了哪些terms, 设置terms=True,还可以加速查询结果高亮的处理

5. 使用查询结果

  scoring:
    一般而言,result文档列表使用score值来排序。whoosh.scoring模块包含了多个不同scoring算法的实现,默认是BM25F.
    当初始化searcher时可以用weighting关键字去替换默认的scoring算法。可以继承WeightingModel实现定制权重算法.
     
    过滤结果:
    对searcher对象的search方法使用filter参数,可以限定results中的允许的文档。也可以使用mask参数对限定results中不允许的文档.参数值可以是query对象,results对象,也可以是承载docnum的set集合。
    
    排序和分类:
    
    对查询结果的排序和分类是基于facet的。在查询结果中的每个文档里的每个facet都会和一个值相关,使用这个数值,可以让你对结果排序或分组。
    
    查询结果在默认情况下,是scoring最高的值排在前面。可以使用在search方法中使用sortedby参数定义其他的条件对查询结果排序。
  
    生成一个可排序的字段:
    为了可以针对某字段排序,在定义schema时,需对该字段添加sortable=True参数.也可以针对没定义sortable=True的字段排序,但是比较没有效率。
         
         
  合并results对象:
    Results.extend(results):把results加在Results后
    Results.filter(results):把results中的文档从Results中移除
    Results.upgrade(results):把出现在results中的Results文档,移到Results的前头
    Results.upgrade_and_extend(result),出现在results中的Results文档,移动到Results的前头,而那些不在Results中的results文档,则添加到Results后头。    

6. 摘要并高亮查询结果

         
  高亮的过程就是一个pipeline的处理过程,和4个元件相关:
    Fragments : 基于匹配的term在文档中的位置,把原始的文档砍成__fragments__
    Scorers: 给每个fragment赋一个分值,允许系统根据分值排出最好的fragment.
    Order functions: 控制展示给用户的fragment,是展示先出现在文档里的fragment,还是展示score最高的fragment.
    Formatters: 把对应的fragment格式化为用户可读格式,如html
           
  在对文本进行高亮处理前,需要去除格式标签,比如:html,和 wiki tags.
      

results = mysearcher.search(myquery)
for hit in results:
    print(hit["title"])
    # Assume "content" field is stored
    print(hit.highlights("content"))

  若高亮的字段没有stored在index中,则需要通过其他途径得到这个字段的text.

        
  whoosh默认仅从文本的前32k字符中抽取fragment. 可以通过调整参数来增加这个值。
  

results = mysearcher.search(myquery)
results.fragmenter.charlimit = 100000


  或者
  

results.fragmenter.charlimit = None 直接关闭限制

  也可以初始化一个定制的framenter, 直接在fragment上设置字符限制:

       

sf = highlight.SentenceFragmenter(charlimit=100000)
results.fragmenter = s

  定制高亮:

  fragment的数量:
  可以使用top参数控制每个文档返回的fragment的数量
  print hit.highlights("content", top=5)
  fragment的size:
  fragmenter的maxchar属性控制fragment的最大长度,默认是200. surround属性控制fragment里关键字前后截取的背景文字长度,默认是20
  

# Allow larger fragments
results.fragmenter.maxchars = 300
# Show more context before and after
results.fragmenter.surround = 50

  Fragmenter:

    Fragmenter控制如何从原始文本中提取摘录文字. Whoosh.hightlight包里已有以下预制的fragmenter:
    whoosh.highlight.ContextFragmenter (默认)
      这是一个默认的智能fragment,可以发现匹配的term, 并抽取周围的文字生成 fragment. 这个fragmenter只产生包含匹配term的fragment.
                
    whoosh.highlight.SentenceFragmenter
      依标点符号,按句子抽取
    whoosh.highlight.WholeFragmenter
      返回整个文本作为fragment,高效(不做处理,当然高效)适合小文本
                
    不同的fragmenter有不同的选项参数
               
  Scorer:
    Scorer是一个可调用的对象,使用fragment作为参数,返回一个可排序的值(值越大,代表该fragment质量越好)。 高亮系统使用这个值去挑选出展示给用户的最佳fragment.
  

 #定义一个新的scorer
def StandardDeviationScorer(fragment):
    """Gives higher scores to fragments where the matched terms are close
        together.
    """
     # Since lower values are better in this case, we need to negate the
     # value
     return 0 - stddev([t.pos for t in fragment.matched])
#使用这个scorer
results.scorer = StandardDeviationScorer         

  

  Order:

    order是一个函数,该函数以fragment为参数,返回一个可排序的值,通过该值对fragment进行排序。
    whoosh.highlight模块有一下的排序函数:
      FIRST(默认的)
      按出现顺序
      SCORE:
                    按得分顺序
                    
    还有其他不常用的: LONGER长fragment优先,SHORTER短fragment优先
                
    使用非默认的排序函数:
    

results.order = hightlight.SCORE

  

  Formatter:

    formatter负责控制分值最高的fragment如何以格式化的方式呈现给用户。通过设置不同的formatter可以返回任何格式,包括:html,genshi事件流,SAX事件生成器,等。
    highlight模块有一下预置实现
    whoosh.highlight.HtmlFormatter
      以带class属性的html标签包围的方式返回匹配的term
    whoosh.highlight.UppercaseFormatter
      把匹配的term以大写字母呈现
    whoosh.highlight.GenshiFormatter
      输出一个genshi事件流
    替换formatter的方式和上面替换其他三个元件的方式一致,更改results.formatter属性即可

  

原文地址:https://www.cnblogs.com/shonelau/p/5805739.html