数据分类:html
一、结构化数据:格式固定,长度固定,数据类型固定,例如:数据库中的数据,java
二、非结构化数据:和上面相反,例如:word文档,pdf文档,邮件,htmlspring
数据的查询:数据库
一、结构化数据的查询:apache
SQL语句,特色:简单,速度快windows
二、非结构化数据的查询:数据结构
把非结构化数据变成结构化数据:先根据空格进行字符串的拆分,获得一个单词列表,基于单词列表建立一个索引(一个为了提升查询速度,建立某种数据结构的集合),查询索引,根据单词和文档的对应关系找到文档列表。工具
应用场景:搜索引擎
一、搜索引擎编码
二、站内搜索
三、电商搜索
四、只要有搜索的地方
lucene:一个基于java开发全文检索的工具包
实现全文检索的流程:
一、建立索引
1·一、得到文档
原始文档:要基于那些数据来进行搜索,那么这些数据就是原始文档
搜索引擎得到文档:使用爬虫得到原始文档
站内搜索得到文档:数据库中的数据
磁盘得到文档:直接使用io流读取磁盘上的文档
1·二、构建文档对象
对应每一个原始文档建立一个Document对象,每一个Document对象中包含多个域,域中保存就是原始文档数据,包含域的名称和值。
注意:每一个文档都有一个惟一的编号,就是文档ID
1·三、分析文档
分词的过程:
一、根据空格进行字符串拆分,获得一个单词列表
二、把单词统一转换成小写
三、去除标点符号
四、去除停用词(无心义的词)
每一个关键词都封装成一个term对象中,包含关键词所在域和关键词自己。
注意:不一样的域中拆分出来的相同的关键词是不一样的term
1·四、建立索引
基于关键词列表建立一个索引,保存到索引库中。索引库中包含:索引,document对象,关键词和文档的对应关系。
补充:经过词语找文档,这种索引的结构叫倒排索引结构。
二、查询索引
2·一、用户查询接口
用户输入查询条件的地方,例如:百度的搜索框
2·二、把关键词封装成一个查询对象,包含:要查询的域和要搜索的关键词
2·三、执行查询,根据要查询的关键词到对应的域上进行搜索
2·四、渲染结果,根据文档的id找到文档对象,对关键词进行处理,最终展现出来
入门代码:
一、添加MAVEN依赖
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- lucene核心库 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>${lunece.version}</version> </dependency> <!-- Lucene的查询解析器 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>${lunece.version}</version> </dependency> <!-- lucene的默认分词器库 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>${lunece.version}</version> </dependency> <!-- lucene的高亮显示 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>${lunece.version}</version> </dependency> </dependencies>
二、代码建立索引
public void createIndex() throws Exception{ File file = new File("./index"); if (!file.exists()){ file.mkdirs(); } /* Directory directory = new RAMDirectory();//把索引库保存到内存中,不推荐 */ //建立一个Director对象,指定索引库保存的位置 Directory directory = FSDirectory.open(file.toPath()); //基于Direcotry对象建立一个indexWriter对象 IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig()); //读取磁盘上的文件,对应每一个文件建立一个文档对象 File orgfile = new File(""); File[] files = orgfile.listFiles(); for (File f : files){ //取文件名 String filename = f.getName(); //文件的路径 String filepath = f.getPath(); //文件的内容 String fileContent = FileUtils.readFileToString(f, "utf-8"); //文件的大小 long filesize = FileUtils.sizeOfDirectory(f); //建立field //参数1:域的名称,参数2:域的内容,参数3:是否存储 Field fieldName = new TextField("name",filename,Field.Store.YES); Field fieldPath = new TextField("path",filepath,Field.Store.YES); Field fieldContent = new TextField("content",fileContent,Field.Store.YES); Field fieldsize = new TextField("size",filesize+"",Field.Store.YES); //建立文档对象 Document document = new Document(); //向文档对象中添加域 document.add(fieldName); document.add(fieldPath); document.add(fieldContent); document.add(fieldsize); //把文档对象写入索引库 indexWriter.addDocument(document); } //关闭indexwriter对象 indexWriter.close(); }
三、索引库搜索
public void searchIndex()throws Exception{ //建立一个Director对象,指定索引库的位置 Directory directory=FSDirectory.open(new File("./index").toPath()); //建立一个indexReader对象 IndexReader indexReader = DirectoryReader.open(directory); //建立一个IndexSearch对象,构造方法中的参数indexReader对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立一个Query对象,TermQuery Query query = new TermQuery(new Term("content","spring")); //执行查询,获得一个TopDocs对象 //参数1:查询对象,参数2:查询结果返回的最大记录数 TopDocs topDocs = indexSearcher.search(query, 10); //取查询结果的总记录数 System.out.println(topDocs.totalHits); //取文档列表 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc doc : scoreDocs){ int docId = doc.doc; Document document = indexSearcher.doc(docId); System.out.println(document.get("name")); System.out.println(document.get("path")); System.out.println(document.get("size")); System.out.println(document.get("content")); } indexReader.close(); }
步骤:
建立索引库
一、建立一个Director对象,指定索引库保存的位置
二、基于Director对象,建立一个IndexWriter对象
三、读取磁盘文件,对应每一个文件建立一个文档对象
四、向文档对象中添加域
五、把文档对象写入索引库
六、关闭indexwriter对象
public void createIndex() throws Exception{ File file = new File("./index"); if (!file.exists()){ file.mkdirs(); } /* Directory directory = new RAMDirectory();//把索引库保存到内存中,不推荐 */ //建立一个Director对象,指定索引库保存的位置 Directory directory = FSDirectory.open(file.toPath()); //基于Direcotry对象建立一个indexWriter对象 IndexWriter indexWriter = new IndexWriter(directory,new IndexWriterConfig()); //读取磁盘上的文件,对应每一个文件建立一个文档对象 File orgfile = new File(); File[] files = orgfile.listFiles(); for (File f : files){ //取文件名 String filename = f.getName(); //文件的路径 String filepath = f.getPath(); //文件的内容 String fileContent = FileUtils.readFileToString(f, "utf-8"); //文件的大小 long filesize = FileUtils.sizeOfDirectory(f); //建立field //参数1:域的名称,参数2:域的内容,参数3:是否存储 Field fieldName = new TextField("name",filename,Field.Store.YES); Field fieldPath = new TextField("path",filepath,Field.Store.YES); Field fieldContent = new TextField("content",fileContent,Field.Store.YES); Field fieldsize = new TextField("size",filesize+"",Field.Store.YES); //建立文档对象 Document document = new Document(); //向文档对象中添加域 document.add(fieldName); document.add(fieldPath); document.add(fieldContent); document.add(fieldsize); //把文档对象写入索引库 indexWriter.addDocument(document); } //关闭indexwriter对象 indexWriter.close(); }
查看索引库:使用luke工具
查询索引库
一、建立一个Director对象,指定索引库的位置
二、建立一个IndexReader对象
三、建立一个IndextSearcher对象,构造方法中的参数IndexReader对象
四、建立一个Query对象,termQuery
五、执行查询,获得一个TopDocs对象
六、取查询结果的总记录数
七、取文档列表
八、打印文档中的内容
九、关闭IndexReader对象
public void searchIndex()throws Exception{ //建立一个Director对象,指定索引库的位置 Directory directory=FSDirectory.open(new File("./index").toPath()); //建立一个indexReader对象 IndexReader indexReader = DirectoryReader.open(directory); //建立一个IndexSearch对象,构造方法中的参数indexReader对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立一个Query对象,TermQuery Query query = new TermQuery(new Term("content","spring")); //执行查询,获得一个TopDocs对象 //参数1:查询对象,参数2:查询结果返回的最大记录数 TopDocs topDocs = indexSearcher.search(query, 10); //取查询结果的总记录数 System.out.println(topDocs.totalHits); //取文档列表 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc doc : scoreDocs){ int docId = doc.doc; Document document = indexSearcher.doc(docId); System.out.println(document.get("name")); System.out.println(document.get("path")); System.out.println(document.get("size")); System.out.println(document.get("content")); } indexReader.close(); } }
分析器:
默认使用的是标准分析器StandardAnalyzer
查看分析器的分析效果:
一、建立一个Analyzer对象,StandardAnayzer对象
二、使用分析器对象的tokenStream方法得到宇哥tokenStream对象
三、向tokenStream对象设置一个引用,至关因而一个指针
四、调用tokenStream对象的rest方法,若是不调用抛异常
五、使用while循环遍历tokenStream对象
六、关闭tokenStream对象
public void testTokenStream() throws Exception{ Analyzer analyzer = new StandardAnalyzer(); TokenStream tokenStream = analyzer.tokenStream("","wo shi yi ge zifuchuang"); CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class); tokenStream.reset(); while (tokenStream.incrementToken()){ System.out.println(charTermAttribute.toString()); } tokenStream.close(); }
中文分析器:IKAnalyzer
一、添加IKAnalyzer的jar包
二、把配置文件和扩展词典添加到工程的classpath下
注意:扩展词典严禁使用windows记事本编辑保证扩展词典的编码格式是utf-8
扩展词典做用:添加一些新词
停用词词典:无心义的词或者是敏感词汇
索引库维护
常见的field:
Field类 |
数据类型 |
Analyzed 是否分词 |
Indexed 是否索引 |
Stored 是否存储 |
说明 |
StringField(FieldName, FieldValue,Store.YES)) |
字符串 |
N |
Y |
Y或N |
这个Field用来构建一个字符串Field,可是不会进行分词,会将整个串存储在索引中,好比(订单号,身份证号等) 是否存储在文档中用Store.YES或Store.NO决定 |
LongField(FieldName, FieldValue,Store.YES) |
Long型 |
Y |
Y |
Y或N |
这个Field用来构建一个Long数字型Field,进行分词和索引,好比(价格) 是否存储在文档中用Store.YES或Store.NO决定 |
StoredField(FieldName, FieldValue) |
重载方法,支持多种类型 |
N |
N |
Y |
这个Field用来构建不一样类型Field 不分析,不索引,但要Field存储在文档中 |
TextField(FieldName, FieldValue, Store.NO) 或 TextField(FieldName, reader)
|
字符串 或 流 |
Y |
Y |
Y或N |
若是是一个Reader, lucene猜想内容比较多,会采用Unstored的策略. |
添加文档:
public class IndexManager { public void addDoucment() throws Exception{ //建立一个IndexWriter对象,须要IKAnalyzer做为分析器 IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); //建立一个document对象 Document document = new Document(); document.add(new TextField("name","新添加的问",Field.Store.YES)); //把文档写入索引库 indexWriter.addDocument(document); indexWriter.close(); } }
删除索引库:
public void deleteAllDocument() throws Exception{ //建立一个IndexWriter对象,须要IKAnalyzer做为分析器 IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); indexWriter.deleteAll(); indexWriter.close(); }
public void deleteDocumentByTerm()throws Exception{ IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); indexWriter.deleteDocuments(new Term("name","内容")); indexWriter.close(); }
更新索引库:
public void updateDocument()throws Exception{ IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File("./index").toPath()), new IndexWriterConfig(new IKAnalyzer())); Document document = new Document(); document.add(new TextField("name","更新的内容",Field.Store.YES)); indexWriter.updateDocument(new Term("name","内容"),document); indexWriter.close(); }
索引库的查询:
使用Query的子类查询
public class SearchIndex { public void testRangeQuery()throws Exception{ IndexReader indexReader = DirectoryReader.open(FSDirectory.open(new File("./index").toPath())); IndexSearcher indexSearcher = new IndexSearcher(indexReader); //建立一个query对象 Query query = LongPoint.newRangeQuery("size", 0l, 10000l); TopDocs topDocs = indexSearcher.search(query, 10); System.out.println(topDocs.totalHits); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs){ int docId = scoreDoc.doc; Document document = indexSearcher.doc(docId); System.out.println(document.get("name")); } indexReader.close(); } }
使用QueryPaser进行查询:能够对要查询的内容先分词,而后基于分词的结果再查询
须要添加jar包lucene-queryoarser
public void testQueryParser()throws Exception{ //建立一个QueryParser对象 //参数1:默认搜索域,参数2:分析器对象 QueryParser queryParser = new QueryParser("name",new IKAnalyzer()); //使用QueryPaser对象建立一个QUery Query query = queryParser.parse("这是一个查询的语句") //执行查询 printResult(query); }