全文搜索
- 结构化数据:具有固定格式或有限长度的数据,如数据库、元数据等
- 非结构化数据(全文数据,文本数据):不定长或无固定格式的数据,如邮件、word文档等
- 半结构化数据:如XML、HTML等,当根据需要可以按结构化数据来处理,也可抽取出纯文本按非结构化数据处理。
全文搜索方式:
- 顺序扫描法:window自带的搜索,在数据库搜索不带索引文本字段等
- 全文检索(索引搜索):对于非结构化数据加上索引,重新组织信息。
特点:
- 做了相关度排序
- 对文本中的关键字做了高亮显示
- 摘要截取
- 基于单词搜索,效果更加精确。如搜索java找不到javascript,因为这是两个单词
- 只关注文本,不考虑语义
使用场景:
- 替换数据库模糊查询。
- 全文索引是搜索引擎的基础
- 只对指定领域的网站搜索进行索引(即垂直索引)
- word、pdf等各种各样的数据格式中检索
- 其他诸如搜狐拼音、Google输入法
分词---语法处理---排序---去重
创建索引:建立单词和句子之间的关系,以便通过单词查询到对应句子的编号。
搜索索引:通过关键字到索引中找到对应的句子编号
输入搜索关键字--分词---搜索得到句子编号---通过编号合并拿到对应的句子---封装成对象的属性传送到前台
Lucene
全文检索的一种实现,也就是工具包(jar)
可以在中小型应用中实现对文本数据的全文搜索,大型应用(Elastic Search)
核心API:
- 增删改:IndexWriter(索引写入器)
- 查:IndexSearcher(索引搜索器)
步骤:
- 下载lucene luncene-5.5.5zip witea-IK-analyzer.zip分词器 pivot-luke-5.5.0-luke-release.zip索引库客户端
- jar导入(核心+分词)
- 测试,创建索引,搜索索引
创建:
给定三个文档(实际开发中要从数据库中查询)
创建IndexWriter
- Director d=FSDirectory.open(Paths.get(常量)) //索引目录。
- IndexWriterConfig conf=new IndexWriterConfig(new SimpleAnalyzer()); //对写入做配置-分词器
- IndexWriter indexWriter=new IndexWriter("d","conf");
把文档放入到Ducument对象的字段中
- Document document1=new Document();
- document1.add(new TextField("id","1",Store.YES));
- document1.add(new TextField("title","doc1",Store.YES));
- 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)
组合查询:与或非