正在用的Neo4j是当前最新版:3.1.0,各种踩坑。说一下如何在Neo4j 3.1.0中使用中文索引。选用了IKAnalyzer做分词器。

1. 首先参考文章:

https://segmentfault.com/a/1190000005665612

里面大致讲了用IKAnalyzer做索引的方式。但并不清晰,实际上,这篇文章的背景是用嵌入式Neo4j,即Neo4j一定要嵌入在你的Java应用中(https://neo4j.com/docs/java-reference/current/#tutorials-java-embedded),切记。否则无法使用自定义的Analyzer。其次,文中的方法现在用起来已经有问题了,因为Neo4j 3.1.0用了lucene5.5,故官方的IKAnalyzer已经不适用了。

2. 修正

转用 IKAnalyzer2012FF_u1.jar,在Google可以下载到(https://code.google.com/archive/p/ik-analyzer/downloads)。这个版本的IKAnalyzer是有小伙伴修复了IKAnalyzer不适配lucene3.5以上而修改的一个版本。但是用了这个包仍有问题,报错提示:

Caused by: java.lang.AbstractMethodError: org.apache.lucene.analysis.Analyzer.createComponents(Ljava/lang/String;)Lorg/apache/lucene/analysis/Analyzer$TokenStreamComponents;

即IKAnalyzer的Analyzer类和当前版本的lucene仍有不适配的地方。

解决方案:再增加两个类


  1. package com.uc.wa.function;
  2. import org.apache.lucene.analysis.Analyzer;
  3. import org.apache.lucene.analysis.Tokenizer;
  4. public class IKAnalyzer5x extends Analyzer{
  5. private boolean useSmart;
  6. public boolean useSmart() {
  7. return useSmart;
  8. }
  9. public void setUseSmart(boolean useSmart) {
  10. this.useSmart = useSmart;
  11. }
  12. public IKAnalyzer5x(){
  13. this(false);
  14. }
  15. public IKAnalyzer5x(boolean useSmart){
  16. super();
  17. this.useSmart = useSmart;
  18. }
  19. /**
  20. protected TokenStreamComponents createComponents(String fieldName, final Reader in) {
  21. Tokenizer _IKTokenizer = new IKTokenizer(in , this.useSmart());
  22. return new TokenStreamComponents(_IKTokenizer);
  23. }
  24. **/
  25. /**
  26. * 重写最新版本的createComponents
  27. * 重载Analyzer接口,构造分词组件
  28. */
  29. @Override
  30. protected TokenStreamComponents createComponents(String fieldName) {
  31. Tokenizer _IKTokenizer = new IKTokenizer5x(this.useSmart());
  32. return new TokenStreamComponents(_IKTokenizer);
  33. }
  34. }


  1. package com.uc.wa.function;
  2. import java.io.IOException;
  3. import org.apache.lucene.analysis.Tokenizer;
  4. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
  5. import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
  6. import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
  7. import org.wltea.analyzer.core.IKSegmenter;
  8. import org.wltea.analyzer.core.Lexeme;
  9. public class IKTokenizer5x extends Tokenizer{
  10. //IK�ִ���ʵ��
  11. private IKSegmenter _IKImplement;
  12. //��Ԫ�ı�����
  13. private final CharTermAttribute termAtt;
  14. //��Ԫλ������
  15. private final OffsetAttribute offsetAtt;
  16. //��Ԫ�������ԣ������Է���ο�org.wltea.analyzer.core.Lexeme�еķ��ೣ����
  17. private final TypeAttribute typeAtt;
  18. //��¼���һ����Ԫ�Ľ���λ��
  19. private int endPosition;
  20. /**
  21. public IKTokenizer(Reader in , boolean useSmart){
  22. super(in);
  23. offsetAtt = addAttribute(OffsetAttribute.class);
  24. termAtt = addAttribute(CharTermAttribute.class);
  25. typeAtt = addAttribute(TypeAttribute.class);
  26. _IKImplement = new IKSegmenter(input , useSmart);
  27. }**/
  28. /**
  29. * Lucene 5.x Tokenizer�������๹�캯��
  30. * ʵ�����µ�Tokenizer�ӿ�
  31. * @param useSmart
  32. */
  33. public IKTokenizer5x(boolean useSmart){
  34. super();
  35. offsetAtt = addAttribute(OffsetAttribute.class);
  36. termAtt = addAttribute(CharTermAttribute.class);
  37. typeAtt = addAttribute(TypeAttribute.class);
  38. _IKImplement = new IKSegmenter(input , useSmart);
  39. }
  40. /* (non-Javadoc)
  41. * @see org.apache.lucene.analysis.TokenStream#incrementToken()
  42. */
  43. @Override
  44. public boolean incrementToken() throws IOException {
  45. //������еĴ�Ԫ����
  46. clearAttributes();
  47. Lexeme nextLexeme = _IKImplement.next();
  48. if(nextLexeme != null){
  49. //��Lexemeת��Attributes
  50. //���ô�Ԫ�ı�
  51. termAtt.append(nextLexeme.getLexemeText());
  52. //���ô�Ԫ����
  53. termAtt.setLength(nextLexeme.getLength());
  54. //���ô�Ԫλ��
  55. offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition());
  56. //��¼�ִʵ����λ��
  57. endPosition = nextLexeme.getEndPosition();
  58. //��¼��Ԫ����
  59. typeAtt.setType(nextLexeme.getLexemeTypeString());
  60. //����true��֪�����¸���Ԫ
  61. return true;
  62. }
  63. //����false��֪��Ԫ������
  64. return false;
  65. }
  66. /*
  67. * (non-Javadoc)
  68. * @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader)
  69. */
  70. @Override
  71. public void reset() throws IOException {
  72. super.reset();
  73. _IKImplement.reset(input);
  74. }
  75. @Override
  76. public final void end() {
  77. // set final offset
  78. int finalOffset = correctOffset(this.endPosition);
  79. offsetAtt.setOffset(finalOffset, finalOffset);
  80. }
  81. }

解决 IKAnalyzer2012FF_u1.jar和lucene5不适配的问题。使用时用IKAnalyzer5x替换IKAnalyzer即可。

3. 最后

Neo4j中文索引建立和搜索示例:


  1. /**
  2. * 为单个结点创建索引
  3. *
  4. * @param propKeys
  5. */
  6. public static void createFullTextIndex(long id, List<String> propKeys) {
  7. log.info("method[createFullTextIndex] begin.propKeys<"+propKeys+">");
  8. Index<Node> entityIndex = null;
  9. try (Transaction tx = Neo4j.graphDb.beginTx()) {
  10. entityIndex = Neo4j.graphDb.index().forNodes("NodeFullTextIndex",
  11. MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "analyzer", IKAnalyzer5x.class.getName()));
  12. Node node = Neo4j.graphDb.getNodeById(id);
  13. log.info("method[createFullTextIndex] get node id<"+node.getId()+"> name<"
  14. +node.getProperty("knowledge_name")+">");
  15. /**获取node详细信息*/
  16. Set<Map.Entry<String, Object>> properties = node.getProperties(propKeys.toArray(new String[0]))
  17. .entrySet();
  18. for (Map.Entry<String, Object> property : properties) {
  19. log.info("method[createFullTextIndex] index prop<"+property.getKey()+":"+property.getValue()+">");
  20. entityIndex.add(node, property.getKey(), property.getValue());
  21. }
  22. tx.success();
  23. }
  24. }


  1. /**
  2. * 使用索引查询
  3. *
  4. * @param query
  5. * @return
  6. * @throws IOException
  7. */
  8. public static List<Map<String, Object>> selectByFullTextIndex(String[] fields, String query) throws IOException {
  9. List<Map<String, Object>> ret = Lists.newArrayList();
  10. try (Transaction tx = Neo4j.graphDb.beginTx()) {
  11. IndexManager index = Neo4j.graphDb.index();
  12. /**查询*/
  13. Index<Node> addressNodeFullTextIndex = index.forNodes("NodeFullTextIndex",
  14. MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "analyzer", IKAnalyzer5x.class.getName()));
  15. Query q = IKQueryParser.parseMultiField(fields, query);
  16. IndexHits<Node> foundNodes = addressNodeFullTextIndex.query(q);
  17. for(Node n : foundNodes){
  18. Map<String, Object> m = n.getAllProperties();
  19. if(!Float.isNaN(foundNodes.currentScore())){
  20. m.put("score", foundNodes.currentScore());
  21. }
  22. log.info("method[selectByIndex] score<"+foundNodes.currentScore()+">");
  23. ret.add(m);
  24. }
  25. tx.success();
  26. } catch (IOException e) {
  27. log.error("method[selectByIndex] fields<"+Joiner.on(",").join(fields)+"> query<"+query+">", e);
  28. throw e;
  29. }
  30. return ret;
  31. }

注意到,在这里我用了IKQueryParser,即根据我们的查询词和要查询的字段,自动构造Query。这里是绕过了一个坑:用lucene查询语句直接查的话,是有问题的。比如:“address:南昌市” 查询语句,会搜到所有带市字的地址,这是非常不合理的。改用IKQueryParser即修正这个问题。IKQueryParser是IKAnalyzer自带的一个工具,但在 IKAnalyzer2012FF_u1.jar却被删减掉了。因此我这里重新引入了原版IKAnalyzer的jar包,项目最终是两个jar包共存的。

到这里坑就踩得差不多了。

       原文地址:https://blog.csdn.net/hereiskxm/article/details/54345261                         </div>

【Neo4j】踩坑大会-Neo4J用中文索引的更多相关文章

  1. PLSQL Developer 中文乱码踩坑记

    环境 操作系统版本: Windows 7 PL/SQL 版本: 12.0.1.1814 原因 由于 Oracle 服务器端和客户端字符集编码不一致引起的. 注意点 写在最前面,减少踩坑!!! 网上教程 ...

  2. Neo4j之坑

    10个月前,我开始用neo4j做cmdb. 初体验下去neo4j很美好. 但是一年中发现一些问题, 仅仅是个人的体验.经供参考 查询语言 如果接触过Neo4j,都会为Cypher的简单和易用感觉到惊叹 ...

  3. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  4. AI相关 TensorFlow -卷积神经网络 踩坑日记之一

    上次写完粗浅的BP算法 介绍 本来应该继续把 卷积神经网络算法写一下的 但是最近一直在踩 TensorFlow的坑.所以就先跳过算法介绍直接来应用场景,原谅我吧. TensorFlow 介绍 TF是g ...

  5. 人工智能(AI)库TensorFlow 踩坑日记之一

    上次写完粗浅的BP算法 介绍 本来应该继续把 卷积神经网络算法写一下的 但是最近一直在踩 TensorFlow的坑.所以就先跳过算法介绍直接来应用场景,原谅我吧. TensorFlow 介绍 TF是g ...

  6. 微信小程序踩坑集合

    1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=1476434678461 2:简易教程:https://mp.weixin.qq.com/debu ...

  7. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  8. Nebula Exchange 工具 Hive 数据导入的踩坑之旅

    摘要:本文由社区用户 xrfinbj 贡献,主要介绍 Exchange 工具从 Hive 数仓导入数据到 Nebula Graph 的流程及相关的注意事项. 1 背景 公司内部有使用图数据库的场景,内 ...

  9. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

随机推荐

  1. 3.2 Redux TodoApp

    上一节讲完了 redux 中的概念,但是仍然没有和 react 联系起来,这一节将利用 redux 在 react 中实现完整的 todolist: 在 react 使用 redux 通过 Provi ...

  2. 13、testng.xml对用例进行分组

    目录如下: TestGroup.java 代码如下: package com.testng.cn; import org.testng.annotations.*; import static org ...

  3. python :Django url /views /Template 文件介绍

    1,Django URL 路由系统 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表:你就是以这种方式告诉Django ...

  4. Day 16 : Python 时间模块[time,]datetime[]及第三方模块的下载与安装

    在进行python程序开发时,除了可以使用python内置的标准模块外,还右许多第三方模块使用,可以在python官网找到. 在使用第三方模块时,需要下载并安装此模块,然后就可以使用标准模块一样导入并 ...

  5. JUC源码分析-集合篇(三)ConcurrentLinkedQueue

    JUC源码分析-集合篇(三)ConcurrentLinkedQueue 在并发编程中,有时候需要使用线程安全的队列.如果要实现一个线程安全的队列有两种方式:一种是使用阻塞算法,另一种是使用非阻塞算法. ...

  6. Pandas之read_excel()和to_excel()函数解析

    read_excel() 加载函数为read_excel(),其具体参数如下. read_excel(io, sheetname=0, header=0, skiprows=None, skip_fo ...

  7. 几何问题 poj 1408

    参考博客: 用向量积求线段焦点证明: 首先,我们设 (AD向量 × AC向量) 为 multi(ADC) : 那么 S三角形ADC = multi(ADC)/2 . 由三角形DPD1 与 三角形CPC ...

  8. git config配置,工作区和版本库联系。

    关于git和github的介绍,我这边不多说. 使用在windows下使用git,需要配置环境变量,也可以使用git自带的终端工具.,打开git bash laoni@DESKTOP-TPPLHIB ...

  9. iOS字符串固定间隔换行

    字符串固定宽度自动换行,之前一直做是没有问题的,可能是这次的字体有些特殊.导致固定宽度下每行的字符个数不一致. 所以每两个字符之间添加换行符 //去除, NSString *name = [theme ...

  10. 2019_7_31python

    练习  输入三条边长如果能构成三角形就计算周长和面积 import math a,b,c = input().split(',') a = float(a) b = float(b) c = floa ...