(三)solr.5.5 配置 IKAnalyzer 中文分词器、合并域进行多维度搜索

安装ik 分词器

准备 ik 分词器使用的 jar 包(下载地址

复制 ik-analyzer-solr5-5.x.jarapache-tomcat-8.5.34/webapp/solr/WEB-INF/lib 

打开 \apache-solr\solr_home\solr_core\conf\managed-schema文件,在最下方追加


<!-- ik 中文分词器 -->
	<fieldType name="text_ik" class="solr.TextField">
		<analyzer>
			 <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" />
		</analyzer>
		<analyzer type="query">
			<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" />
		</analyzer>
	</fieldType>
	<!-- ik 中文分词器 end -->

或者(我使用的是第一种代码

<fieldType name="text_ik" class="solr.TextField">   
  <analyzer type="index" useSmart="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>   
  <analyzer type="query" useSmart="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>   
</fieldType>

<!-- 属性说明 -->
   <!-- 
     name:域的名称
     class:指定solr的类型,
     analyzer:分词器配置
        type:index(索引分词器),query(查询分词器)
        tokenizer:配置分词器
        filter:过滤器
   -->

 

重启 tomcat 就可以看到  分词器字段:text_ik

验证一下中文分词效果

如果启动tomcat 报如下的错

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.3:compile (default-compile) on project ik-analyzer-solr5: Fatal error compiling: invalid target release: 1.8 -> [Help 1]

检查你的JAVA_HOME。如果JAVA_HOME存在,则可能不是JAVA8。

 

配置动态域 dynamicField

何谓动态域呢?就是这个域的名称,是由表达式组成的,只要名称满足了这个 表达式,就可以用这个域

 同样的认识一下这些属性

 name:域的名称,该域的名称是通过一个表达式来指定的,只要符合这这个规则,就可以使用这个域。比如  aa_i,bb_i,13_i等等,只要满足这个表达式皆可

 type:对应的值类型,相应的值必须满足这个类型,不然就会报错

 indexed:是否要索引

 stored:是否要存储

 ...其它的属性与普通的域一致

 

主键域 uniqueKey

<uniqueKey>id</uniqueKey>

用于确定和执行文档唯一性的字段,除非该字段标记为必需的“false”,否则将是必填字段,不能随便更改

 

复制域 copyField

<copyField source="company_name" dest="keywords_list"/>

source是源域,dest 是目标域,意思是将源域的内容复制到目标域中

目标域必须是允许多值的,如下,nultiValued必须为true,因为可能多个源域对应一个目标域,所以它需要以数组来存储

<field name="keywords_list" type="text_ik" indexed="true" stored="false"  multiValued="true"/>

现在我们用field来配置实际的业务字段,建立一个测试数据表

打开 data-config.xml 新增一个 employee_info 的 entity节点

<dataConfig>
    <dataSource type="JdbcDataSource" name="dataSource1" driver="com.mysql.jdbc.Driver"       
	url="jdbc:mysql://localhost/james" user="root" password="root" />
    <document>
        <entity name="article" pk="id" 
		query="select id,title,author,type from article"
		deltaImportQuery="select * from article where id ='${dih.delta.id}'"
        deltaQuery="select id from article where update_time  > '${dataimporter.last_index_time}'">
		<field name="id" column="id"/>
		<field name="title" column="title"/>
		<field name="author" column="author"/>
		<field name="type" column="type"/> 
		<field name="update_time" column="update_time"/> 
        </entity>
		
		<entity name="employee_info" pk="id" 
		query="select id,company_name,user_name,industry,position from employee_info"
		deltaImportQuery="select * from employee_info where id ='${dih.delta.id}'"
        deltaQuery="select id from employee_info where update_time  > '${dataimporter.last_index_time}'">
		<field name="id" column="id"/>
		<field name="company_name" column="company_name"/>
		<field name="user_name" column="user_name"/>
		<field name="industry" column="industry"/> 
		<field name="position" column="position"/> 
		<field name="update_time" column="update_time"/> 
        </entity>
    </document>
</dataConfig>

配置 managed-schema 文件,id 和 updata_time 共用,不需要再新增一个,主要看 employee_info的配置,将需要分词的域类型改成我们前面配置过的 “text_ik”

<!-- 主键的id就不需要配置了,默认已经把id配置为主键了,默认的配置如下 -->
   <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> 
   <field name="update_time" type="date" indexed="true" stored="true" omitNorms="true" />
   
   <!-- article -->
   <field name="title" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="author" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="type" type="string" indexed="true" stored="true" omitNorms="true" /> 
  
	<!-- employee_info -->
   <field name="company_name" type="text_ik" indexed="true" stored="true" omitNorms="true"/>
   <field name="user_name" type="text_ik" indexed="true" stored="true" omitNorms="true"/>
   <field name="industry" type="text_ik" indexed="true" stored="true" omitNorms="true" /> 
   <field name="position" type="text_ik" indexed="true" stored="true" omitNorms="true" />

前面我们只说了复制域的属性,没有了解它的应用场景,我们举个例子来说明一下:

用户在搜索框搜索的时候,有可能输入的是商品名称,也有可能输入的是商品描述,也有可能输入的是一个商品类型,那么这些值的搜索,肯定在后台是对应一个域的,那么既然如此,我们就可以把这些域合并成一个,这样在后台只需要单独的对这一个域进行搜索就可以了

先定义一个目标域

<field name="keywords_list" type="text_ik" indexed="true" stored="false"  multiValued="true"/> 

将商品名称、描述、类型复制到上面定义的目标域(类型名和例子的描述不一样,不要太在意)

 <copyField source="company_name" dest="keywords_list"/>
   <copyField source="user_name" dest="keywords_list"/>
   <copyField source="industry" dest="keywords_list" /> 
   <copyField source="position" dest="keywords_list" />

保存,然后重启tomcat,打开 http://localhost:8080/solr/admin.html

 

在过滤条件处添加刚才复制域的 名称(keywords_list)后面接想要输入的关键字

 

使用SolrJ

既然是开发,当然需要使用代码来操作solr,SolrJ 是一个用来访问solr的java客户端,是一个可以和solr轻松对话的API,SolrJ隐藏了许多连接到Solr的细节,并允许你的应用程序通过简单的高级方法与Solr进行交互。

        <dependency>
            <groupId>org.apache.solr</groupId>
            <artifactId>solr-solrj</artifactId>
            <version>5.0.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>compile</scope>
        </dependency>

SolrCient 是抽象的,所以连接远程Solr的时候,会创建一个HttpSolrClient 或 CouldSolrClient的实例,两者间通过Http与Solr通信,

不同之处在于HttpSolrClient使用明确的Solr URL进行配置,而CloudSolrClient是使用 SolrCloud 群集的 zkHost 字符串配置的。

 

单节点 Solr 客户端

配置指向具体 Solr 的索引库的 HTTP 路径,并实例化 HttpSolrClient 创建客户端

    private static final String URL = "http://127.0.0.1:8080/solr/solr_core";
    private HttpSolrClient solrClient = null;

    @Before
    public void init() {
        solrClient = new HttpSolrClient(URL);
    }

执行查询

    @Test
    public void testQuery() {
        String queryStr = "*:*";
        SolrQuery params = new SolrQuery(queryStr);
        params.setStart(0);
        params.setRows(10);
        //输入单个条件进行查询
        params.setQuery("keywords_list:董事*");
        //输入多个条件进行查询
//       params.setFilterQueries("company_name:阿里*","user_name:马*");
        params.setFilterQueries("");
        //排序
        params.setSort("id", SolrQuery.ORDER.asc);
        //只读取指定的属性,可写多个也可用逗号分开,默认显示全部
//      params.setFields("id","company_name","user_name","industry");
        try {
            QueryResponse response = null;
            response = solrClient.query(params);
            SolrDocumentList list = response.getResults();
            System.out.println("########### 总共 : " + list.getNumFound() + "条记录");
            for (SolrDocument doc : list) {
                System.out.println("{id:" + doc.get("id") + ",company_name:" + doc.get("company_name") + ",user_name:" + doc.get("user_name") + ",industry:" + doc.get("industry") + ",position:" + doc.get("position") + "}");
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        }
    }

增加、修改的方法是一样的,创建一个 SolrInputDocument并将其传递到SolrClient的add()方法中,如果 Solr索引库 里存在提交的数据是修改,不存在是增加

 

    @Test
    public void addAndUpdateDoc() throws IOException, SolrServerException {
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id", 7);
        doc.addField("company_name", "字节跳动科技有限公司");
        doc.addField("user_name", "张某某");
        doc.addField("industry", "互联网");
        doc.addField("position", "CEO");
        UpdateResponse rsp = solrClient.add(doc);
        UpdateResponse rspCommit = solrClient.commit();
        System.out.println("commit doc to index" + " result:" + rspCommit.getStatus() + "     Qtime:" + rspCommit.getQTime());
    }

删除方法,可以删除单个、多个,也可以根据查询条件删除

  @Test
    public void deleteDoc() throws IOException, SolrServerException {
//       solrClient.deleteById("15");//删除单个
        solrClient.deleteById(Arrays.asList("6", "12")); //批量删除
        
//       solrClient.deleteByQuery("position:ceo");
        solrClient.commit();
    }

不管是 query(),delete(),还是add(),commit() 以后才能生效

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值