全文搜索

  • 结构化数据:具有固定格式或有限长度的数据,如数据库、元数据等
  • 非结构化数据(全文数据,文本数据):不定长或无固定格式的数据,如邮件、word文档等
  • 半结构化数据:如XML、HTML等,当根据需要可以按结构化数据来处理,也可抽取出纯文本按非结构化数据处理。

全文搜索方式:

  • 顺序扫描法:window自带的搜索,在数据库搜索不带索引文本字段等
  • 全文检索(索引搜索):对于非结构化数据加上索引,重新组织信息。

特点:

  1. 做了相关度排序
  2. 对文本中的关键字做了高亮显示
  3. 摘要截取
  4. 基于单词搜索,效果更加精确。如搜索java找不到javascript,因为这是两个单词
  5. 只关注文本,不考虑语义

使用场景:

  • 替换数据库模糊查询。
  • 全文索引是搜索引擎的基础
  • 只对指定领域的网站搜索进行索引(即垂直索引)
  • word、pdf等各种各样的数据格式中检索
  • 其他诸如搜狐拼音、Google输入法
分词---语法处理---排序---去重
创建索引:建立单词和句子之间的关系,以便通过单词查询到对应句子的编号。

搜索索引:通过关键字到索引中找到对应的句子编号
输入搜索关键字--分词---搜索得到句子编号---通过编号合并拿到对应的句子---封装成对象的属性传送到前台

Lucene

全文检索的一种实现,也就是工具包(jar)
可以在中小型应用中实现对文本数据的全文搜索,大型应用(Elastic Search)

核心API:

  • 增删改:IndexWriter(索引写入器)
  • 查:IndexSearcher(索引搜索器) 
步骤
  1. 下载lucene  luncene-5.5.5zip   witea-IK-analyzer.zip分词器  pivot-luke-5.5.0-luke-release.zip索引库客户端
  2. jar导入(核心+分词)
  3. 测试,创建索引搜索索引

创建:

给定三个文档(实际开发中要从数据库中查询)


创建IndexWriter
  1. Director d=FSDirectory.open(Paths.get(常量))    //索引目录。
  2. IndexWriterConfig conf=new IndexWriterConfig(new SimpleAnalyzer()); //对写入做配置-分词器
  3. IndexWriter indexWriter=new IndexWriter("d","conf");
把文档放入到Ducument对象的字段中
  1. Document document1=new Document();
  2. document1.add(new TextField("id","1",Store.YES));
  3. document1.add(new TextField("title","doc1",Store.YES));
  4. document1.add(new TextField("content","doc1",Store.YES));
三个文档,要创建三个Document对象

通过IndexWriter把Document写入
  • indexWriter.addDocument(document1);    //添加到缓存区
  • indexWriter.addDocument(document2);
  • indexWriter.addDocument(document3);
  • indexWriter.commit(); //提交
  • indexWriter.close();  //关闭

搜索:

创建搜索器IndexSearcher
  • Directory d=FSDirectory.open(Paths.get(PATH));
  • IndexReader reader=DirectoryReader.open(d)  //索引读入器
  • IndexSearcher searcher=new IndexSearcher(reader);  //索引搜索器
创建Query对象--把特定格式的字符串解析得到
  • String parseStr="content:java";
  • QueryParser parser=new QueryParser("content",new SimpleAnalyzer());
  • Query query=parser.parse(parseStr); 
使用IndexSearcher传入Query进行搜索
  • TopDocs topDocs=searcher.searche(query,1000);查询top n个数据
  • topDocs.totalHits; //返回命中数
通过从结果中获取documentId,再通过它获取document
  • ScoreDoc[] scoreDoce=topDocs.scoreDocs;返回命中数组,进行遍历,获取文档的编号
  • scoreDoce.doc; //返回id
  • 通过id获取对象,searcher.doc(docId)
把document转换成想要的对象进行返回----document.get("id")

lucene API详解:

索引目录:Directory

存放索引文件目录的抽象,要用到它的子类:
FSDirectory:文件系统目录,通过磁盘目录来获取。
   MMapDirectory:内存映射目录
   NIOFSDirectory:linux支持
   SimpleDirectory:window支持
正常来说我们的代码要根据系统运行环境来选择合适的Directory,其实在open方法中已经做了逻辑判断
RAMDirectory:内存目录

分词器:

对一段文本进行单词拆分,拆分的效果取决于对应的分词器。
准备三个文本:

按照特定的分词器进行分词:(分词器,文本)两个参数    推荐使用IK分词器
导入IK分词器jar包 (jar包+配置文件[IKAnalyzer.cfg.xml    stopword.dic])中文停止器      扩展词
testAnalyzer(new IKAnalyzer(),str)    

Document  IndexableField

Document是文档,当想要往索引库添加一些信息的时候,就要封装为Document,再来进行添加。
提供的方法:
add()
remove()
get  getBinaryValue   getField   getFields

IndexableField: 是一个接口()
可索引的字段,相当于数据库的列  new Field("content",doc,type)  
new FieldType()    .setStore(true)是否在数据区存储,如果前台要获取该字段就要存储
                                .IndexOption是否要建立索引,判断前台是否要做查询
                               Tokenized是否支持分词,内容是否支持分词创建索引,看是否是专有名词(成都,地名                                  不需要分词)
两个子类:StringField  不分词的字符串,地名。
                  TextField   分词字符串  标题,内容……

Document的CRUD

随着数据库的改变而改变
创建  indexWriter.addDocument()
删除  indexWriter.deleteDoeuments(new Term("content","lucene"))
修改  indexWriter.update(new Term("content","lucene"),)

获取(根据文档ID)
查询(前台查询)

Query以及Searcher
通配符查询,用*,?
模糊查询,~2  允许错两个
最大间隔数 setSlot(2)
组合查询:与或非