【Solr】全文检索框架

1 Solr的简介和原理

Solr是什么

Solr是全文检索的的框架,基于Apache Lucene(全文检索工具库)实现搜索。

为什么使用Solr

在海量数据下,对MySQL或Oracle进行模糊查询或条件查询的效率是很低的。既然使用关系型数据库进行搜索效率比较低,最直接的解决方案就是使用专用搜索工具进行搜索,从而提升搜索效率。

Solr的作用

  • Solr:可扩展索引、搜索功能、高亮显示和文字解析功能。
  • Solr本质就是一个Java web 项目,且内嵌了Jetty服务器,所以安装起来非常方便。客户端操作Solr的过程和平时我们所写项目一样,就是请求Solr中控制器,处理完数据后把结果响应给客户端。

正向索引和反向索引

  • 正向索引:从文档内容到词组的过程。每次搜索的时候需要搜索所有文档,每个文档比较搜索条件和词组。
文档词组
I am a chineseI,am,a,chinses
  • 反向索引:是正向索引的逆向。建立词组和文档的映射关系。通过找到词组就能找到文档内容。(和新华字典找字很像)
词组文档
I,am,a,chinsesI am a chinese

Solr的搜索原理

  • Solr能够提升检索效率的主要原因就是分词和索引(反向索引)。
  • 分词:会对搜索条件/存储内容进行分词,分成日常所使用的词语。
  • 索引:存储在Solr中内容会按照程序员的要求来是否建立索引。如果要求建立索引会把存储内容中关键字(分词)建立索引。
    在这里插入图片描述

Solr的数据存储说明

  • 在开发中需要把数据添加到Solr中进行初始化,每次修改完数据库中数据还需要同步Solr中的数据。
  • Solr中数据存储是存储在Document对象中,对象中可以包含的属性和属性类型都定义在schema.xml中。如果需要自定义属性或自定义属性类型都需要修改schema.xml配置文件。从Solr5开始schema.xml更改名称为managed-schema(没有扩展名)。

2 Solr的安装

Solr是用java编写,因此需要先安装JDK

如没有JDK必须先安装JDK。

上传并解压

上传压缩包solr-8.2.0.tgz到/usr/local/tmp中。并进行解压

# cd /usr/local/tmp
# tar zxf solr-8.2.0.tgz

修改启动参数

# /usr/local/tmp/solr-8.2.0/bin
# vim solr.in.sh

在这里插入图片描述

启动Solr

Solr内嵌Jetty,直接启动即可。默认监听8983端口。
Solr默认不推荐root账户启动,如果是root账户启动需要添加-force参数。

# ./solr start -force

启动过程中出现的问题

问题1:找不到solr.log文件

在这里插入图片描述

解决方法:
  • 在/usr/local/tmp/solr-8.2.0/server/logs/下新建此文件

问题2:local host name unknown

在这里插入图片描述

原因:主机名与hosts文件中对不上导致此问题
解决方法
  • 查看当前主机名,执行命令 hostname
    在这里插入图片描述
  • 编辑hosts文件,执行命令 vi /etc/hosts,将原有的主机名改为当前主机名
    在这里插入图片描述
    在这里插入图片描述

可视化管理界面

在关闭防火墙的前提下,可以在windows的浏览器中访问Solr。
输入: http://192.168.244.10:8983 就可以访问Solr的可视化管理界面。其中左侧菜单,分别为:

  • Dashboard:面板显示Solr的总体信息。
  • Logging:日志
  • Core Admin:Solr的核心。类似于数据的Database
  • Java Perperties:所有Java相关属性。
  • Thread Dump:线程相关信息。
  • 如果有Core,将显示在此处。

3 IK中文分词器的安装

首先去https://search.maven.org/search?q=com.github.magese下载对应版本的ik-analyzer。

上传

上传ik-analyzer-8.2.0.jar到 /usr/local/solr/server/solr-webapp/webapp/WEB-INF/lib目录中。

修改配置文件

修改/usr/local/solr/server/solr/testcore/conf/managed-schema

# vim /usr/local/solr/server/solr/testcore/conf/managed-schema

添加下面内容

<field name="myfield" type="text_ik" indexed="true" stored="true" />
    <fieldType name="text_ik" class="solr.TextField">
            <analyzer type="index">
                    <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf"/>
                    <filter class="solr.LowerCaseFilterFactory"/>
            </analyzer>
            <analyzer type="query">
                    <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" conf="ik.conf"/>
                    <filter class="solr.LowerCaseFilterFactory"/>
            </analyzer>
    </fieldType>

在这里插入图片描述

重启

# cd /usr/local/solr/bin
# ./solr stop -all
# ./solr start -force

如果分词不成功需要在managed-schema中添加一下字段。
在这里插入图片描述

4 数据库导入插件

配置数据导入插件-dataimport

思路:要让solr支持dataimport插件,首先需要在solr的核心配置文件里面加载插件,因为dataimport插件需要从数据库里面获得数据,所以需要配置数据库信息。

导入相关的jar包

  • 在solr的dist文件夹下找到如下jar包。放在webapp\WEB-INF\lib
    在这里插入图片描述
  • 连接数据需要mysql的驱动的支持,使用5.1.* 这个版本
    在这里插入图片描述

在配置文件中增加配件的配置

需要修改solr的core里面的conf目录下的solrconfig.xml,增加插件的配置

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

配置数据库连接配置文件

配置数据库连接的配置文件 data-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<dataConfig>
	<dataSource type="JdbcDataSource"   
			driver="com.mysql.jdbc.Driver"   
			url="jdbc:mysql://192.168.244.10:3306/products"   
			user="root"   
			password="123456"/>
	<document>
		<entity name="product" query="SELECT pid,name,price from products">
			 <field column="pid" name="id"/>
			 <field column="name" name="name"/>
			 <field column="price" name="price"/>
		</entity>
	</document>
</dataConfig>

5 查询条件说明

在这里插入图片描述

6 使用solrj操作solr

导入依赖

<dependency>
    <groupId>org.apache.solr</groupId>
    <artifactId>solr-solrj</artifactId>
    <version>8.2.0</version>
</dependency>

solrj操作solr

public class SolrJClient {
    public static void main(String[] args) {
//        add();
//        delete();
        query();
    }

    //查询
    public  static  void query () {
        HttpSolrClient client = null;
        try {
            //创建客户端
            String url = "http://192.168.244.10:8983/solr/testcore";
            client = new HttpSolrClient.Builder(url).build();

            //创建查询对象
            SolrQuery query = new SolrQuery();
            //添加查询条件
            query.set("q", "name:家天下");
            query.add("fq","catalog_name:与钟不同");
            query.addSort("price", SolrQuery.ORDER.desc);
            query.setStart(0);
            query.setRows(6);

            //设置高亮数据
            query.setHighlight(true);
            query.addHighlightField("name");
            query.setHighlightSimplePre("<font style='color:blue'>");
            query.setHighlightSimplePost("</font>");

            //查询
            QueryResponse response = client.query(query);

            //获取查询结果
            SolrDocumentList results = response.getResults();
            //获取高亮数据
            Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();

            for (SolrDocument result : results) {
                //获取高亮数据
                Map<String, List<String>> map = highlighting.get(result.get("id"));
                List<String> highlightingName = map.get("name");
                System.out.println("id:" + result.get("id"));
                System.out.println("高亮:" + highlightingName);
                System.out.println("名字:" + result.get("name"));
                System.out.println("类别:" + result.get("catalog_name"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //删除
    public static void delete () {
        HttpSolrClient client = null;
        try {
            //创建客户端
            String url = "http://192.168.244.10:8983/solr/testcore";
            client = new HttpSolrClient.Builder(url).build();

            client.deleteById("8");

            client.commit();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //添加
    public static void add () {
        HttpSolrClient client = null;
        try {
            //1 创建客户端
            String url = "http://192.168.244.10:8983/solr/testcore";
            client = new HttpSolrClient.Builder(url).build();
            //2 创建要保存的duixang
            SolrInputDocument fieldDoc = new SolrInputDocument();
            fieldDoc.addField("id", 2500);
            fieldDoc.addField("myself", "myself");

            //3 执行事务保存
            client.add(fieldDoc);

            //4 执行事务
            client.commit();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7 使用spring data solr操作solr

导入依赖

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

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

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

配置文件

#配置solr服务器所在的地址
spring.data.solr.host=http://192.168.244.10:8983/solr

spring data solr操作solr

@SpringBootTest(classes = {SpringdataSolrApplication.class})
@RunWith(SpringRunner.class)
class SpringdataSolrApplicationTests {

    @Autowired(required = false)
    private SolrTemplate solrTemplate;

    //简单查询
    @Test
    public void query() {
        System.out.println("welcome .....");
        SimpleQuery simpleQuery = new SimpleQuery();
        //设置条件名
        Criteria criteriaName = new Criteria("name");
        //expression:分词查询
        criteriaName.expression("家天下");

        Criteria criteriaPrice = new Criteria("price");
        //区间查询
        criteriaPrice.between(1,100);

        Criteria criteriaCatalog = new Criteria("catalog_name");
        criteriaCatalog.is("与钟不同");

        simpleQuery.addCriteria(criteriaName);
        simpleQuery.addCriteria(criteriaPrice);
        simpleQuery.addCriteria(criteriaCatalog);

        simpleQuery.setOffset(0L);
        simpleQuery.setRows(5);

        //查询
        ScoredPage<Product> products = solrTemplate.queryForPage("testcore", simpleQuery, Product.class);
        System.out.println("==============================");
        for (Product product : products) {
            System.out.println(product.getName());
        }
    }

    @Test
    public void highQuery () {
        SimpleHighlightQuery highlightQuery = new SimpleHighlightQuery();

        //设置条件名
        Criteria criteriaName = new Criteria("name");
        //expression:分词查询
        criteriaName.expression("家天下");

        highlightQuery.addCriteria(criteriaName);

        //设置高亮条件
        HighlightOptions options = new HighlightOptions();
        options.addField("name");
        options.setSimplePrefix("----我是前缀----");
        options.setSimplePostfix("----我是后缀----");
        //将高亮条件设置给query
        highlightQuery.setHighlightOptions(options);

        HighlightPage<Product> highlightProducts = solrTemplate.queryForHighlightPage("testcore", highlightQuery, Product.class);

        List<HighlightEntry<Product>> list = highlightProducts.getHighlighted();
        ArrayList<Product> results = new ArrayList<>();
        for (HighlightEntry<Product> entry: list) {
            //获取entry中的高亮数据集合
            List<HighlightEntry.Highlight> highlights = entry.getHighlights();
            //获取没有经过高亮处理的结果对象
            Product product = entry.getEntity();
            for (HighlightEntry.Highlight highlight : highlights) {
                //判断数据数据的字段是否是需要的
                if (highlight.getField().getName().equals("name")) {
                    //获取高亮的字符串
                    String string = highlight.getSnipplets().get(0);
                    product.setName(string);
                }
            }
            results.add(product);
        }
        for (int i = 0; i < results.size(); i++) {
            System.out.println(results.get(i));
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值