Solr通过特殊字符分词实现自定义分词器详解

前言

我们在对英文句子分词的时候,一般采用采用的分词器是WhiteSpaceTokenizerFactory,有一次因业务要求,需要根据某一个特殊字符(以逗号分词,以竖线分词)分词。感觉这种需求可能与WhiteSpaceTokenizerFactory相像,于是自己根据Solr源码自定义了分词策略。

业务场景

有一次,我拿到的数据都是以竖线“|”分隔,分词的时候,需要以竖线为分词单元。比如下面的这一堆数据:

有可能你拿到的是这样的数据,典型的例子就是来自csv文件的数据,格式和下面这种类似:

分词思路

在Solr的schema.xml文件中,有这样的配置

<fieldType name="text_ws" class="solr.TextField" positionIncrementGap="100">
 <analyzer>
  <tokenizer class="solr.WhitespaceTokenizerFactory"/>
 </analyzer>
</fieldType>

对于字段类型text_ws,指定了一个分词器工厂WhitespaceTokenizerFactory,根据这个类,可以实现通过空格来分词,那么我通过竖线分词的代码应该与之类似。

修改源码

在Java工程中引入如下jar包:

<dependency>
  <groupId>org.apache.solr</groupId>
  <artifactId>solr-core</artifactId>
  <version>6.0.0</version>
</dependency>

参照WhitespaceTokenizerFactory的源码,写一个自己的MyVerticalLineTokenizerFactory,内容基本不变:

package com.trainning.project.custom;

import java.util.Arrays;
import java.util.Collection;
import java.util.Map;

import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.core.UnicodeWhitespaceTokenizer;
import org.apache.lucene.analysis.util.TokenizerFactory;
import org.apache.lucene.util.AttributeFactory;

/**
* @author JiangChao
* @date 2017年4月2日下午3:41:13
*/
public class MyVerticalLineTokenizerFactory extends TokenizerFactory{
 public static final String RULE_JAVA = "java";
 public static final String RULE_UNICODE = "unicode";
 private static final Collection<String> RULE_NAMES = Arrays.asList(RULE_JAVA, RULE_UNICODE);

 private final String rule;

 /** Creates a new MyVerticalLineTokenizerFactory */
 public MyVerticalLineTokenizerFactory(Map<String,String> args) {
  super(args);

  rule = get(args, "rule", RULE_NAMES, RULE_JAVA);

  if (!args.isEmpty()) {
  throw new IllegalArgumentException("Unknown parameters: " + args);
  }
 }

 @Override
 public Tokenizer create(AttributeFactory factory) {
  switch (rule) {
  case RULE_JAVA:
   return new MyVerticalLineTokenizer(factory);
  case RULE_UNICODE:
   return new UnicodeWhitespaceTokenizer(factory);
  default:
   throw new AssertionError();
  }
 }
}

具体做分词的MyVerticalLineTokenizer代码如下

package com.trainning.project.custom;

import org.apache.lucene.analysis.util.CharTokenizer;
import org.apache.lucene.util.AttributeFactory;

/**
* @author JiangChao
* @date 2017年4月2日下午9:46:18
*/
public class MyVerticalLineTokenizer extends CharTokenizer {

 public MyVerticalLineTokenizer() {

 }
 public MyVerticalLineTokenizer(AttributeFactory factory) {
  super(factory);
  }

  /** Collects only characters which do not satisfy
  * 参数c指的是term的ASCII值,竖线的值为 124
  */
  @Override
  protected boolean isTokenChar(int c) {
  return !(c == 124);
  }
}

这里最主要的方法就是isTokenChar,它控制了分词的字符,如果需要使用逗号分词的话,字需要将这个方法修改成下面这样:

 /** Collects only characters which do not satisfy
  * 参数c指的是term的ASCII值,逗号的值为 44
  */
  @Override
  protected boolean isTokenChar(int c) {
  return !(c == 44);
  }

整合

代码写好了,怎么使用呢?首先,需要把刚才的java文件打成jar包。我使用的是Eclipse,直接选中两个类文件,右键 -> Export -> JAR File -> Select the export destination: ->选择输出路径,填一个jar名字:MyVerticalLineTokenizerFactory -> Finish

得到的MyVerticalLineTokenizerFactory.jar文件大约3KB,将改文件放置到.\solr_home\lib下,在shcema.xml中定义自己的field

<fieldType name="vertical_text" class="solr.TextField">
 <analyzer>
  <tokenizer class="com.trainning.project.custom.MyVerticalLineTokenizerFactory"/>
 </analyzer>
 </fieldType>
 <field name="custom" type="vertical_text" indexed="true" stored="false"/>

注意这里的class是刚才自己写的分词器的完整类名。

打开Solr主页,在Analysis页面测试一下,是否实现了预期?

源码下载:

GitHub:下载地址

本地下载:链接地址

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • java多线程处理执行solr创建索引示例

    复制代码 代码如下: public class SolrIndexer implements Indexer, Searcher, DisposableBean { //~ Static fields/initializers ============================================= static final Logger logger = LoggerFactory.getLogger(SolrIndexer.class); private static fi

  • 详解java整合solr5.0之solrj的使用

    1.首先导入solrj需要的的架包 2.需要注意的是低版本是solr是使用SolrServer进行URL实例的,5.0之后已经使用SolrClient替代这个类了,在添加之后首先我们需要根据schema.xml配置一下我们的分词器 这里的msg_all还需要在schema.xml中配置 它的主要作用是将msg_title,msg_content两个域的值拷贝到msg_all域中,我们在搜索的时候可以只搜索这个msg_all域就可以了, solr默认搜索需要带上域,比如 solr更改默认搜索域的地

  • 详解spring中使用solr的代码实现

    在介绍solr的使用方法之前,我们需要安装solr的服务端集群.基本上就是安装zookeeper,tomcat,jdk,solr,然后按照需要配置三者的配置文件即可.由于本人并没有具体操作过如何进行solr集群的搭建.所以关于如何搭建solr集群,读者可以去网上查看其它资料,有很多可以借鉴.这里只介绍搭建完solr集群之后,我们客户端是如何访问solr集群的. 之前介绍过,spring封装nosql和sql数据库的使用,都是通过xxxTemplate.solr也不例外. 我们需要引入solr的j

  • solr在java中的使用实例代码

    SolrJ是操作Solr的Java客户端,它提供了增加.修改.删除.查询Solr索引的JAVA接口.SolrJ针对 Solr提供了Rest 的HTTP接口进行了封装, SolrJ底层是通过使用httpClient中的方法来完成Solr的操作. jar包的引用(maven pom.xml): <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId

  • django Model层常用验证器及自定义验证器详解

    在Django中,对数据进行校验有两种方式:一种是通过Form校验,一种是通过Model校验.在此,我对Model中的校验方法做下记录. 示例之前补充以下几点: 1.Django数据校验方式分为以下三步: Model.clean_fields() 验证字段基本规则比如长度格式等: Model.clean() 可自定义验证条件和报错信息: Model.validate_unique() 为验证添加的唯一性约束. 2.此三步验证通过调用full_claen(exclude=None, validat

  • java 类加载与自定义类加载器详解

    类加载 所有类加载器,都是ClassLoader的子类. 类加载器永远以.class运行的目录为准. 读取classpath根目录下的文件有以下几种方式: 1 在Java项目中可以通过以下方式获取classspath下的文件: public void abc(){ //每一种读取方法,使用某个类获取Appclassloader ClassLoader cl = ReadFile.class.getClassLoader(); URL url = cl.getResource("a.txt&quo

  • python中的迭代器,生成器与装饰器详解

    目录 迭代器 生成器 装饰器 总结 迭代器 每一个可迭代类内部都要实现__iter__()方法,返回一个迭代类对象,迭代类对象则定义了这个可迭代类如何迭代. for循环调用list本质上是是调用了list的迭代器进行迭代. # 对list进行for循环本质上是调用了list的迭代器 list = [1,2,3,4] # for 循环调用 for elem in list: print(elem) # 迭代器调用 list_iter = list.__iter__() while True: tr

  • C++11新增的包装器详解

    目录 function bind function 目前,我们的知识深度已知的可调用对象类型有: 函数指针 仿函数 / 函数对象 lambda表达式 现在我们有一个函数模板 template<class F, class T> T useF(F f, T x) { static int count = 0; cout << "count:" << &count << endl; return f(x); } 对于函数模板,编译器会

  • 基于Spring-AOP实现自定义分片工具详解

    目录 1.背景 2.Spring-AOP 3.功能实现 3.1 MethodPartAndRetryer 3.2 RetryUtil 3.3 RetryAspectAop 4.功能使用 4.1 配置文件 4.2 代码示例 5.小结 1.背景 随着数据量的增长,发现系统在与其他系统交互时,批量接口会出现超时现象,发现原批量接口在实现时,没有做分片处理,当数据过大时或超过其他系统阈值时,就会出现错误.由于与其他系统交互比较多,一个一个接口去做分片优化,改动量较大,所以考虑通过AOP解决此问题. 2.

  • unified如何处理markdown解析器详解

    目录 unified是什么 unified生态简介 工作原理 Parse Transform Stringify 牛刀小试 环境搭建 处理ESM类型包 最简用法 加载文档meta 一个实际使用例子: unified是什么 unified是用于文档处理的生态系统,核心包提供了文档处理的流程控制,具体功能由生态系统中各个插件提供.例如我们如果需要处理markdown,就需要使用markdown处理相关的插件.当然除了markdwon以外,还提供了处理HTML.JSX等的插件.其良好的扩展能力能让我们

  • fastjson序列化时间自定义格式示例详解

    目录 Java8 的日期相关 API 首先建一个项目添加依赖 配置类中注入 Spriing 容器 写个接口做下测试 Java8 的日期相关 API Java8 的日期相关 API用起来是真香,但免不了遇到在用旧版 1.0 API 的情况.这不,跟另一个部门做对接,人家说你发过来的时间怎么带个 T,我这边没法解析...我回头就是一句xxx,情绪发泄完该做的事咱也得做不是,下面就看看怎么处理这个问题. 首先建一个项目添加依赖 <dependencies> <dependency> &l

  • Angularjs自定义指令Directive详解

    今天学习angularjs自定义指令Directive. Directive是一个非常棒的功能.可以实现我们自义的的功能方法. 下面的例子是演示用户在文本框输入的帐号是否为管理员的帐号"Admin". 在网页上放一个文本框和一个铵钮: <form id="form1" name="form1" ng-app="app" ng-controller="ctrl" novalidate> <i

  • Android使用xml自定义图片实例详解

    Android使用xml自定义图片实例详解 实现效果图: 白色圆角图片 bg_round_rectangle_white.xml <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <!-

  • Android启动内置APK和动态发送接收自定义广播实例详解

    Android启动内置APK和动态发送接收自定义广播实例详解 工作中遇到这样一个需求,需要为按键添加一个亲情号,提供一个接口启动内置的APK,思考再三决定更改Framework,利用广播机制去实现. 一.代码动态自主启动内置APK 我们都知道Android系统为我们提供了很多服务管理类,PackageManager主要是管理应用程序包,通过它就可以获取应用程序信息并构建Intent,启动对应的应用.除此之外Android还未我们提供了一些对应的类来管理相关的xml文件,比如说可以通过Packag

随机推荐