欢迎投稿

今日深度:

Solr简介与Solr搜索与分页,

Solr简介与Solr搜索与分页,


1.solr简介

solr是以lucene为内核开发的企业级搜索应用 应用程序可以通过http请求方式来提交索引,查询索引,提供了比lucene更丰富的查询语言,是一个高性能,高可用环境全文搜索引擎

2.倒排索引的原理

  • 实例文章表
文章id 文章标题 文章内容
1 我爱中国 中国地大物博
2 香港是中国一部分 香港的英文是hongkong
索引    文章id
我       11
中国     1,2
香港     22
一部分   2

3.分词器

  1. 将中文拆分成有意义的词 常用的IK分词器,庖丁解牛分词器。

4.lucene

  1. lucene是一个将text数据类型,分词建立索引的一个库,不适合企业级使用,企业级考虑高可用问题。

  2. solr是一个企业级应用的搜索引擎,支持使用json格式提交数据。

  3. json格式:

  4. [] 代表数组

  5. {} 对象(文档 document)

  6. 键值对 属性

  7. 模拟json

[
 {
    id:1,
    title:'我爱中国',
    content:'中国地大物博'
  },
 {
    id:2,
    title:'香港是中国一部分',
    content:'香港的英文是hongkong'
  }
]
  1. solr高可用版本参考网址:
    https://blog.csdn.net/liaomin416100569/article/details/77301756

5.solr安装(docker)

核(core):是用于存储json格式的数据,等价于mysql中数据库的概念。
文档:一个json对象就是一个文档 相同属性的json数组集合就是一个表。
检测端口命令: netstat -aon | grep 8983 下载netstat :yum -y install net-tools telnet

[root@localhost ~]# docker exec -it --user=solr my_solr bin/solr create_core -c mycore

Copying configuration to new core instance directory:
/opt/solr/server/solr/mycore

Creating new core 'mycore' using command:
http://localhost:8983/solr/admin/cores?action=CREATE&name=mycore&instanceDir=mycore

{
  "responseHeader":{
    "status":0,
    "QTime":2137},
  "core":"mycore"}

6.solr搜索

  • q表示按照什么字段来搜索
  • 字段名:值 (where 列名=值)
  • 支持or 和and语法
  • 比如 i:1 and j:2
  • 模拟数据

7.solr中文分词器配置

  • 默认solr 没有使用中文分词器 所有搜索的词 都是整个句子就是一个词 搜索时 将单词全部写入才能搜索或者使用* 需要配置中文分词器
  • 目前比较好用的分词器 是IK 2012年停更 只支持到 Lucene4.7 所有 solr5.5 需要lucene5支持 需要修改部分源码来支持solr5.5
<dependencies>
   	<dependency>
   		<groupId>org.apache.lucene</groupId>
   		<artifactId>lucene-analyzers-common</artifactId>
   		<version>5.5.5</version>
   	</dependency>
   	
   	<dependency>
   		<groupId>org.apache.lucene</groupId>
   		<artifactId>lucene-core</artifactId>
   		<version>5.5.5</version>
   	</dependency>
   	<dependency>
   		<groupId>org.apache.lucene</groupId>
   		<artifactId>lucene-queryparser</artifactId>
   		<version>5.5.5</version>
   	</dependency>
   	<dependency>
   		<groupId>com.janeluo</groupId>
   		<artifactId>ikanalyzer</artifactId>
   		<version>2012_u6</version>
   	</dependency>


   </dependencies>
  1. 重写IKAnalyzer类和IKTokenizer类
    注意这里建包必须是:org.wltea.analyzer.lucene
    IKAnalyzer类(类名必须要一样)
//修改后的类
package org.wltea.analyzer.lucene;


import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Tokenizer;

/**
 * IK分词器,Lucene Analyzer接口实现
 * 兼容Lucene 4.0版本
 */
public final class IKAnalyzer extends Analyzer {

  private boolean useSmart;

  public boolean useSmart() {
    return useSmart;
  }

  public void setUseSmart(boolean useSmart) {
    this.useSmart = useSmart;
  }

  /**
   * IK分词器Lucene  Analyzer接口实现类
   *
   * 默认细粒度切分算法
   */
  public IKAnalyzer() {
    this(false);
  }

  /**
   * IK分词器Lucene Analyzer接口实现类
   *
   * @param useSmart 当为true时,分词器进行智能切分
   */
  public IKAnalyzer(boolean useSmart) {
    super();
    this.useSmart = useSmart;
  }

  /**
   * 重载Analyzer接口,构造分词组件
   */
  @Override
  protected TokenStreamComponents createComponents(String fieldName) {
    Tokenizer _IKTokenizer = new IKTokenizer(this.useSmart());
    return new TokenStreamComponents(_IKTokenizer);
  }

}

IKTokenizer类(同上)

/**
 * IK 中文分词  版本 5.0.1
 * IK Analyzer release 5.0.1
 * 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * 源代码由林良益(linliangyi2005@gmail.com)提供
 * 版权声明 2012,乌龙茶工作室
 * provided by Linliangyi and copyright 2012 by Oolong studio
 * 

 * 
 */
package org.wltea.analyzer.lucene;

import java.io.IOException;
import java.io.Reader;

import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;

import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

/**
 * IK分词器 Lucene Tokenizer适配器类
 * 兼容Lucene 4.0版本
 */
public final class IKTokenizer extends Tokenizer {

  // IK分词器实现
  private IKSegmenter _IKImplement;

  // 词元文本属性
  private final CharTermAttribute termAtt;
  // 词元位移属性
  private final OffsetAttribute offsetAtt;
  // 词元分类属性(该属性分类参考org.wltea.analyzer.core.Lexeme中的分类常量)
  private final TypeAttribute typeAtt;
  // 记录最后一个词元的结束位置
  private int endPosition;

  /**
   * Lucene 4.0 Tokenizer适配器类构造函数
   * @param in
   * @param useSmart
   */
  public IKTokenizer(boolean useSmart) {
    offsetAtt = addAttribute(OffsetAttribute.class);
    termAtt = addAttribute(CharTermAttribute.class);
    typeAtt = addAttribute(TypeAttribute.class);
    _IKImplement = new IKSegmenter(input, useSmart);
  }

  /*
   * (non-Javadoc)
   * @see org.apache.lucene.analysis.TokenStream#incrementToken()
   */
  @Override
  public boolean incrementToken() throws IOException {
    // 清除所有的词元属性
    clearAttributes();
    Lexeme nextLexeme = _IKImplement.next();
    if (nextLexeme != null) {
      // 将Lexeme转成Attributes
      // 设置词元文本
      termAtt.append(nextLexeme.getLexemeText());
      // 设置词元长度
      termAtt.setLength(nextLexeme.getLength());
      // 设置词元位移
      offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition());
      // 记录分词的最后位置
      endPosition = nextLexeme.getEndPosition();
      // 记录词元分类
      typeAtt.setType(nextLexeme.getLexemeTypeString());
      // 返会true告知还有下个词元
      return true;
    }
    // 返会false告知词元输出完毕
    return false;
  }

  /*
   * (non-Javadoc)
   * @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader)
   */
  @Override
  public void reset() throws IOException {
    super.reset();
    _IKImplement.reset(input);
  }

  @Override
  public final void end() {
    // set final offset
    int finalOffset = correctOffset(this.endPosition);
    offsetAtt.setOffset(finalOffset, finalOffset);
  }
}

  1. 将ikanalyzer里的IKAnalyzerClass文件和IKTokenizerClass文件替换成自己写的Class文件(记得去你自己的镜像仓库拿原jar包)

    替换到

将替换好的jar包上传到linux里面
6. 进入你放jar包的目录在执行拷贝命令:docker cp ./ikanalyzer-2012_u6.jar my_solr:/opt/solr/server/solr-webapp/webapp/WEB-INF/lib (将linux拷贝过来的jar包拷进server/solr-webapp/webapp/WEB-INF/lib目录下)
7. 重启容器: docker stop my_solr(关闭) docker start my_solr(开启)
8. 拷贝my_solr容器里的managed-schema文件到linux /opt/ika/目录下去修改,配置文分词 命令:docker cp my_solr:/opt/solr/server/solr/mycore/conf/managed-schema ./
9. 修改文件 managed-schema

 定义分词器数据类型
     <fieldType name="text_ik" class="solr.TextField" >
     
 <analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>   
  
    <analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/> 
  
  </fieldType>
 
  定义动态字段
  <dynamicField name="*_ik" type="text_ik" indexed="true" stored="true"/>
    //index代表倒排索引
	//stored代表存储数据
  1. 修改完成把文件拷贝回原目录:docker cp ./managed-schema my_solr:/opt/solr/server/solr/mycore/conf/
  2. 重启容器
  3. 进行引擎搜索测试
    图1

    图2

8.数据库数据迁移solr

  • cp /opt/solr/dist/solr-dataimporthandler-5.5.5.jar /opt/solr/server/solr-webapp/webapp/WEB-INF/lib
  • cp /opt/solr/dist/solr-dataimporthandler-extras-5.5.5.jar /opt/solr/server/solr-webapp/webapp/WEB-INF/lib
  • exit退出 下载jar包当前目录(https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.24)
    docker cp ./mysql-connector-java-5.1.24.jar my_solr:/opt/solr/server/solr-webapp/webapp/WEB-INF/lib
  1. 新建data-c.xml创建连接数据的四要素
<?xml version="1.0" encoding="UTF-8"?> 

<dataConfig>  

<dataSource name="source1" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://192.168.1.3:3306/test" user="root" password="123456" batchSize="-1" />  
  <document>  
      
   <entity name="book" pk="newid"  dataSource="source1"   
              query="select * from  mynew" >
  
      <field column="newid" name=""/>  
      
  <field column="newtitle" name="title_ik"/>  
 
   </entity>

</document> 

</dataConfig>

4.创建成功后拷贝到my_solr:/opt/solr/server/solr/mycore/conf目录下 命令:docker cp ./data-c.xml my_solr:/opt/solr/server/solr/mycore/conf
5. 修改solrconfig.xml 指定data-c.xml文件
6. docker cp my_solr:/opt/solr/server/solr/mycore/conf/solrconfig.xml . 把要修改的文件拷贝到当前目录

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">  
 
     <lst name="defaults">  
       
  	<str name="config">data-c.xml</str>  
   
   </lst> 
 
 </requestHandler>


修改成功后拷贝回原地方: docker cp ./solrconfig.xml my_solr:/opt/solr/server/solr/mycore/conf 重启:docker restart my_solr

9.代码实现Solr查询与分页

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.11.RELEASE</version>
	</parent>
	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-solr</artifactId>
		</dependency>

	</dependencies>
  1. 创建资源文件连接linux 里面的solr
spring: 
  data: 
    solr: 
      host: http://192.168.163.131:8983/solr
server: 
  port: 8888 
  1. 创建main方法
package cn.pkl;

import org.apache.solr.client.solrj.SolrClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.solr.core.SolrTemplate;

@SpringBootApplication
public class SokrMain {

	@Bean
	 public SolrTemplate solrTemplate(SolrClient client) {
	    return new SolrTemplate(client);

	}
	public static void main(String[] args) {
		SpringApplication.run(SokrMain.class, args);

	}

}

  1. 创建dao层接口
package cn.pkl.dao;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;

import cn.pkl.entity.Person;

public interface MoneyDap extends SolrCrudRepository<Person, String> {
	//方法名必须固定(findBy+字段名)
	//public List<Person> findByDesc(String keyword); 
	//分页查询加排序
	//public Page<Person> findByDesc(String keyword,Pageable page); 
	//单独排序
	public List<Person> findByDesc(String keyword,Sort sor); 
	
	@Query("name_ik:?0")
	public List<Person> queryByDesc(String keyword); 
	
}

  1. 创建实体类
package cn.pkl.entity;

import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.solr.core.mapping.SolrDocument;

@SolrDocument(solrCoreName="mycore")
public class Person {
	private String id;
	@Field("country_ik")
	private String country;
	@Field("name_ik")
	private String name;
	@Field("desc_ik")
	private String desc;
	@Field("age_i")
	private int age;
	
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDesc() {
		return desc;
	}
	public void setDesc(String desc) {
		this.desc = desc;
	}
	
	
	
}

  1. 创建控制层
package cn.pkl.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.pkl.dao.MoneyDap;
import cn.pkl.entity.Person;

@RestController
public class SolrController {
	/*@Autowired
	private SolrTemplate st;
	
	@GetMapping("/queryMoney")
	public List<Money> queryMoney(String keyword) {
		SimpleQuery sq=new SimpleQuery("uname_ik:"+keyword);
		Page<Money>  query=st.query(sq, Money.class);
		return query.getContent();
	}*/
	@Autowired
	private MoneyDap my;
	//自动查询
	/*@GetMapping("/queryMoney")
	public List<Person> findByUname(String keyword) {
		List<Person> findByDesc = my.findByDesc(keyword);
		return findByDesc;
	}*/
	//根据名字查询
	/*@GetMapping("/queryMoney")
	public List<Person> findByUname(String keyword) {
		List<Person> findByDesc = my.queryByDesc(keyword);
		return findByDesc;
	}*/
	//分页查询 加排序
	/*@GetMapping("/queryMoney")
	public Page<Person> findByUname(String keyword) {
		PageRequest qr=new PageRequest(0, 2,new Sort(Direction.ASC,"age_i"));
		
		Page<Person> findByDesc = my.findByDesc(keyword,qr);
		return findByDesc;
	}*/
	//单独排序
	@GetMapping("/queryMoney")
	public List<Person> findByUname(String keyword) {
		List<Person> findByDesc = my.findByDesc(keyword,new Sort(Direction.ASC,"age_i"));
		return findByDesc;
	}
}

7.创建HTML页面(记得写在static文件下面)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
</script>
<script type="text/javascript">
	function query(){
		$.ajax({
			url:'queryMoney',
			dataType:'json',
			type:'get',
			data:'keyword='+$("#b").val(),
			success:function(r){
				$("#a").html(JSON.stringify(r));
			}
		});
	}
</script>
</head>
<body>
	
		新闻:<input id="b" type="text" name="keyword"><button onclick="query()">搜索</button>
		<div id="a">
		
		</div>
	
</body>
</html>

www.htsjk.Com true http://www.htsjk.com/solr/29735.html NewsArticle Solr简介与Solr搜索与分页, 1.solr简介 solr是以lucene为内核开发的企业级搜索应用 应用程序可以通过http请求方式来提交索引,查询索引,提供了比lucene更丰富的查询语言,是一个高性能,...
相关文章
    暂无相关文章
评论暂时关闭