数据库检索效率时,一般首要优化途径是从索引入手,然后根据需求再考虑更复杂的负载均衡、读写分离和分布式水平/垂直分库/表等手段;
索引通过信息冗余来提高检索效率,其以空间换时间并会降低数据写入的效率;因此对索引字段的选择非常重要。

  • Neo4j可对指定Label的Node Create Index,当新增/更新符合条件的Node属性时,Index会自动更新。Neo4j Index默认采用Lucene实现(可定制,如Spatial Index自定义实现的RTree索引),但默认新建的索引只支持精确匹配(get),模糊查询(query)的话需要以全文索引,控制Lucene后台的分词行为。
  • Neo4j全文索引默认的分词器是针对西方语种的,如默认的exact查询采用的是lucene KeywordAnalyzer(关键词分词器),fulltext查询采用的是 white-space tokenizer(空格分词器),大小写什么的对中文没啥意义;所以针对中文分词需要挂一个中文分词器,如IK Analyzer,Ansj,至于类似梁厂长家的基于深度学习的分词系统pullword,那就更厉害啦。

本文以常用的IK Analyzer分词器为例,介绍如何在Neo4j中对字段新建全文索引实现模糊查询。


IKAnalyzer分词器

IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。
IKAnalyzer3.0特性:

  • 采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和最大词长两种切分模式;具有83万字/秒(1600KB/S)的高速处理能力。
  • 采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符优化的词典存储,更小的内存占用。支持用户词典扩展定义
  • 针对Lucene全文检索优化的查询分析器IKQueryParser(作者吐血推荐);引入简单搜索表达式,采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率。
    IK Analyser目前还没有maven库,还得自己手动下载install到本地库,下次空了自己在github做一个maven私有库,上传这些maven central库里面没有的工具包。

IKAnalyzer自定义用户词典

  • 词典文件
    自定义词典后缀名为.dic的词典文件,必须使用无BOM的UTF-8编码保存的文件。
  • 词典配置
    词典和IKAnalyzer.cfg.xml配置文件的路径问题,IKAnalyzer.cfg.xml必须在src根目录下。词典可以任意放,但是在IKAnalyzer.cfg.xml里要配置对。如下这种配置,ext.dic和stopword.dic应当在同一目录下。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
    <properties>
    <comment>IK Analyzer 扩展配置</comment>
     
    <!--用户可以在这里配置自己的扩展字典 -->
    <entry key="ext_dict">/ext.dic;</entry>
     
    <!--用户可以在这里配置自己的扩展停止词字典-->
    <entry key="ext_stopwords">/stopword.dic</entry>
    </properties>

Neo4j全文索引构建

指定IKAnalyzer作为luncene分词的analyzer,并对所有Node的指定属性新建全文索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[@Override](/user/Override)
public void createAddressNodeFullTextIndex () {
try (Transaction tx = graphDBService.beginTx()) {
IndexManager index = graphDBService.index();
Index<Node> addressNodeFullTextIndex =
index.forNodes( "addressNodeFullTextIndex", MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "analyzer", IKAnalyzer.class.getName()));
 
ResourceIterator<Node> nodes = graphDBService.findNodes(DynamicLabel.label( "AddressNode"));
while (nodes.hasNext()) {
Node node = nodes.next();
//对text字段新建全文索引
Object text = node.getProperty( "text", null);
addressNodeFullTextIndex.add(node, "text", text);
}
tx.success();
}
}

Neo4j全文索引测试

对关键词(如’有限公司’),多关键词模糊查询(如’苏州 教育 公司’)默认都能检索,且检索结果按关联度已排好序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package uadb.tr.neodao.test;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.helpers.collection.MapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.wltea.analyzer.lucene.IKAnalyzer;
 
import com.lt.uadb.tr.entity.adtree.AddressNode;
import com.lt.util.serialize.JsonUtil;
 
/**
* AddressNodeNeoDaoTest
*
* [@author](/user/author) geosmart
*/
@RunWith(SpringJUnit4ClassRunner. class)
@ContextConfiguration(locations = { "classpath:app.neo4j.cfg.xml" })
public class AddressNodeNeoDaoTest {
[@Autowired](/user/Autowired)
GraphDatabaseService graphDBService;
 
[@Test](/user/Test)
public void test_selectAddressNodeByFullTextIndex() {
try (Transaction tx = graphDBService.beginTx()) {
IndexManager index = graphDBService.index();
Index<Node> addressNodeFullTextIndex = index.forNodes("addressNodeFullTextIndex" ,
MapUtil. stringMap(IndexManager.PROVIDER, "lucene", "analyzer" , IKAnalyzer.class.getName()));
IndexHits<Node> foundNodes = addressNodeFullTextIndex.query("text" , "苏州 教育 公司" );
for (Node node : foundNodes) {
AddressNode entity = JsonUtil.ConvertMap2POJO(node.getAllProperties(), AddressNode. class, false, true);
System. out.println(entity.getAll地址实全称());
}
tx.success();
}
}
}

CyperQL中使用自定义全文索引查询

正则查询

1
2
3
4
profile
match (a:AddressNode{ruleabbr:'TOW',text:'唯亭镇'})<-[r:BELONGTO]-(b:AddressNode{ruleabbr:'STR'})
where b.text=~ '金陵.*'
return a,b

全文索引查询

1
2
3
4
5
profile
START b=node:addressNodeFullTextIndex("text:金陵*")
match (a:AddressNode{ruleabbr:'TOW',text:'唯亭镇'})<-[r:BELONGTO]-(b:AddressNode)
where b.ruleabbr='STR'
return a,b

LegacyIndex中建立联合exact和fulltext索引

对label为AddressNode的节点,根据节点属性ruleabbr的分类addressnode_fulltext_index(省->市->区县->乡镇街道->街路巷/物业小区)/addressnode_exact_index(门牌号->楼幢号->单元号->层号->户室号),对属性text分别建不同类型的索引

1
2
3
4
profile
START a=node:addressnode_fulltext_index("text:商业街"),b=node:addressnode_exact_index("text:二期19")
match (a:AddressNode{ruleabbr:'STR'})-[r:BELONGTO]-(b:AddressNode{ruleabbr:'TAB'})
return a,b limit 10

原文地址:http://neo4j.com.cn/topic/58184ea2cdf6c5bf145675c3

Neo4j中实现自定义中文全文索引的更多相关文章

  1. Neo4j中實現自定義中文全文索引

    資料庫檢索效率時,一般首要優化途徑是從索引入手,然後根據需求再考慮更復雜的負載均衡.讀寫分離和分散式水平/垂直分庫/表等手段:索引通過資訊冗餘來提高檢索效率,其以空間換時間並會降低資料寫入的效率,因此 ...

  2. solr服务中集成IKAnalyzer中文分词器、集成dataimportHandler插件

    昨天已经在Tomcat容器中成功的部署了solr全文检索引擎系统的服务:今天来分享一下solr服务在海量数据的网站中是如何实现数据的检索. 在solr服务中集成IKAnalyzer中文分词器的步骤: ...

  3. MySQL中文全文索引插件 mysqlcft 1.0.0 安装使用文档[原创]

    [文章+程序 作者:张宴 本文版本:v1.0 最后修改:2008.07.01 转载请注明原文链接:http://blog.zyan.cc/post/356/] MySQL在高并发连接.数据库记录数较多 ...

  4. 安装完Linux Mint后,发现系统中竟没有中文输入法

    安装完Linux Mint后,发现系统中竟没有中文输入法,语言支持之后自动更新过程中有些安装包下载失败. 可以采取下面的方法安装上中文输入法. 1. 安装iBus: sudo add-apt-repo ...

  5. UWP中实现自定义标题栏

    UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...

  6. Entity Framework 6 Recipes 2nd Edition(10-5)译 -> 在存储模型中使用自定义函数

    10-5. 在存储模型中使用自定义函数 问题 想在模型中使用自定义函数,而不是存储过程. 解决方案 假设我们数据库里有成员(members)和他们已经发送的信息(messages) 关系数据表,如Fi ...

  7. Android XML中引用自定义内部类view的四个why

    今天碰到了在XML中应用以内部类形式定义的自定义view,结果遇到了一些坑.虽然通过看了一些前辈写的文章解决了这个问题,但是我看到的几篇都没有完整说清楚why,于是决定做这个总结. 使用自定义内部类v ...

  8. ASP.NET Core中显示自定义错误页面-增强版

    之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...

  9. Web(Jsp+ Servlet)开发中如何解决中文乱码问题

    1.中文乱码的成因 编码的字符集和解码的字符集不一致. 2.web开发过程中可能出现的乱码的位置及解决方案 ①request乱码 在向服务器传递数据时,所传递的中文有可能出现乱码. post请求(协议 ...

随机推荐

  1. Java-Class-C:org.springframework.util.Assert

    ylbtech-Java-Class-C:org.springframework.util.Assert 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部 1. /* * Copyr ...

  2. 14、java实现poi操作excel,包括读和写日期格式,并且设置字体样式

    1.首先大家来看导出的结果 下边就是导出的代码了 protected void testExcel() throws IOException{ String path=getServletContex ...

  3. Ethenet: MAC PHY MII RMII

    https://www.cnblogs.com/liangxiaofeng/p/3874866.html 1. general 下图是网口结构简图.网口由CPU.MAC和PHY三部分组成.DMA控制器 ...

  4. Git 学习第四天

    我们已经知道,通过命令 git remote add origin git@github.com/Your.name/file.git 可以连接远程仓库,那么,假如我现在想切换另个一远程仓库的连接应该 ...

  5. java实现邮件定时发送

    最近做项目时客户提出了一个需求:系统定时发送E-mail到其客户,达到通知的效果.先将实例分享给大家,如果确实有一些帮助的话,请大家来点掌声! 首先介绍java定时器(java.util.Timer) ...

  6. Feign 系列(03)Feign 工作原理

    目录 Feign 系列(03)Feign 工作原理 1. Feign 是如何设计的 2. Feign 动态代理 2.1 ReflectiveFeign 构建 2.2 生成代理对象 2.3 Method ...

  7. Rsync 恢复 libselinux.SO.1

    libselinux.SO.1  这个文件对 CentOS 7很重要, 误删掉后,会导致很多命令无法使用(比如yum ,rpm  命令),利用rsync这个工具来修复. 服务端执行如下配置:(选取正常 ...

  8. python学习10—迭代器、三元表达式与生成器

    python学习10—迭代器.三元表达式与生成器 1. 迭代器协议 定义:对象必须提供一个next方法,执行该方法或者返回迭代中的下一项,或者返回一个StopIteration异常,以终止迭代(只能往 ...

  9. [USACO06JAN]牛的舞会The Cow Prom

    题目描述 The N (2 <= N <= 10,000) cows are so excited: it's prom night! They are dressed in their ...

  10. 百度网盘不限速下载PanDownload网页版+IDM

    1.安装配置IDM 下载链接:链接:https://pan.baidu.com/s/13P4ae-IPgi5Y13CGEZgmlg 提取码:do44 安装后在浏览器(推荐chrome或Firefox) ...