Erlang实战建立文本索引

开发 开发工具
我们今天将改进作者以前建立文本索引的方式,使用ETS来存储单词及其索引列表,同时拆分词使用Erlang提供的string:token模块,更加灵活和可移植性。

为文本建立索引是文本信息处理的一个重要的任务,给定一个由英文单词构成的文件,为文件中所有单词建立索引,记录每个单词出现的行号和每行出现的次数,并将索引存入一个文件。在Erlang实战练习(六)中我强调了当时建立文本索引的时候太粗糙,一是使用了尽量规避的进程字典的方式;二是分词使用的是正则表达式,不够灵活。本文将改进我以前建立文本索引的方式,使用ETS来存储单词及其索引列表,同时拆分词使用Erlang提供的string:token模块,更加灵活和可移植性。

word_index.erl文件的总体结构如下:

  1. -module(word_index).    
  2. -export([start/2]).    
  3. -import(re, [run/2,replace/4]).    
  4. -import(string,[substr/3]).   
  5. %% start两个参数:FileIn表示要建立索引的文本文件,FileOut表示索引保存的目标文件start(FileIn,FileOut) ->  
  6.     {_First,Second} = file:open(FileIn,read),%% 只读打开FileIn文件   
  7. if 
  8.         _First =:= ok ->  
  9.             LineList = readFile(Second,0),%% 函数readFile/2的功能是将文本以行为单位,存入列表                
  10. %io:format("~nfile contents:~p~n",[LineList]),  
  11.             TableID = ets:new(index,[ordered_set]),%% ets:new创建一个“键值”搜索表,
  12. 存储键值映射元祖,设置表名为index,表的类型为ordered_set                
  13. index(FileOut,LineList,TableID);%% 为文本中的每一行建立单词索引              
  14. _First =/= ok ->  
  15.             io:format("Open file error: file doesn't exist!")  
  16.     end.  

readFile/2函数代码如下:

  1. %% 读取文本每一行,以{Line,LineNo}为元组存入列表中readFile(S, LineNo) -> readFile(S,LineNo,[]).  
  2.  
  3. readFile(S, LineNo, Ret) ->  
  4.     UpdateLineNo = LineNo +1,  
  5.     OneLine = io:get_line(S,''),%% 读取文件中的一行内容      if 
  6.         OneLine =:= eof ->  
  7.              io:format("Read file EOF!"),  
  8.              file:close(S),  
  9.              lists:reverse(Ret);  
  10.         OneLine =/= eof ->  
  11.             readFile(S,UpdateLineNo, [{OneLine,UpdateLineNo} | Ret])  
  12.     end. 

index/3函数代码如下:

  1. index(File,LineList,TableID) ->  
  2.     if 
  3.         length(LineList) =:= 0 ->  
  4.             ToList = ets:tab2list(TableID),  
  5.             io:format("index is:~n~p~n",[ToList]),  
  6.             writeToFile(File,ToList),  
  7.             io:format("create index success! ");  
  8.         length(LineList) =/= 0 ->  
  9.             First = lists:nth(1,LineList),  
  10.             processOneLine(First,TableID),  
  11.             index(File,lists:delete(First, LineList), TableID)              
  12.     end.  
  13.  
  14. %% 处理一行文本processOneLine(OneLine, TableID) ->  
  15.     {Element, LineNo } = OneLine,  
  16.     %io:format("Line no:~p~n",[LineNo]),  
  17.     Words = string:tokens(Element,"\n\t "),  
  18.     matchWords(Words,LineNo,TableID).  
  19.  
  20. matchWords([], LineNo, TableID) ->   
  21.     io:format("process line(~p) success!~n",[LineNo]);  
  22.       
  23. matchWords(Words, LineNo, TableID) ->  
  24.     %io:format("Words:~p~n",[Words]),  
  25.     Word = lists:nth(1,Words),  
  26.     _Value = ets:lookup(TableID,Word),%%返回值为匹配Word的元组列表       if 
  27.         length(_Value) =:= 0 -> %% Word还未被索引,直接插入此Word索引                ets:insert(TableID,{Word,[{LineNo,1}]} );  
  28.         length(_Value) =/= 0 -> %% Word已被索引,更新Word索引列表                 KVs = lists:nth(1,_Value),  
  29.             Value = element(2,KVs),  
  30.             ets:insert(TableID,{Word, insertRec(Value,LineNo) } )  
  31.     end,  
  32.     matchWords(lists:delete(Word, Words), LineNo, TableID).  
  33.  
  34. %% 处理行号与出现次数元组列表insertRec(List,LineNo) -> insertRec(List,LineNo,length(List)).  
  35.  
  36. insertRec(List, LineNo, 0) ->   
  37.     [{LineNo, 1} |List];  
  38. insertRec(List, LineNo, Ret) ->  
  39.     First = lists:nth(Ret,List),  
  40.     {LN, Num} = First,  
  41.     if 
  42.         LN =:= LineNo ->  
  43.             Temp = lists:delete(First, List),  
  44.             [{LineNo, Num+1} | Temp];  
  45.         LN =/= LineNo ->  
  46.             insertRec(List, LineNo, Ret-1)  
  47.     end.  
  48.              
  49.  
  50. %% 将索引写入文件writeToFile(File,ToList) ->  
  51.     {ok,S} = file:open(File,write),  
  52.     lists:foreach(fun(X) -> io:format(S,"~p.~n",[X]) end, ToList),  
  53.     file:close(S). 

至此,我已经将使用ets存储键值大型表来存储单词索引列表的程序讲完了,大家自己回去动手试验吧。本文是继续上文的一个续篇,是一种改进的建立文本索引方式。以后我还好继续通过实战练习来探讨Erlang的学习与总结思考,谢谢大家的关注。

原文:http://www.cnblogs.com/itfreer/archive/2012/05/07/Erlang_in_practise_index.html

【编辑推荐】

  1. Erlang之父Joe Armstrong访谈:程序调试与啤酒
  2. Scala和Erlang,以及多核主导的未来
  3. Erlang面向分布与并发的编程语言
  4. 看Erlang中Actor模型的执行方式和优劣
  5. Erlang视点:并行计算和云计算
责任编辑:彭凡 来源: 博客园
相关推荐

2012-05-08 13:42:24

Erlang

2012-05-14 13:58:19

Erlang

2010-11-29 10:22:46

Sybase建立索引

2010-05-31 12:31:42

MySQL建立索引

2011-08-16 13:27:34

索引

2011-08-15 18:20:05

建立索引SQL Sever数据

2024-03-01 09:57:19

数据库检索项目

2010-09-06 17:08:23

2013-11-25 15:12:26

iOS开发

2012-12-04 10:29:47

PostgreSQL索引

2010-09-17 14:13:20

SIP业务Erlang

2010-10-26 16:54:16

oracle全文索引

2011-04-01 15:36:24

索引SQL Server

2010-08-06 13:26:29

DB2建立databa

2018-05-08 18:26:49

数据库MySQL性能

2022-02-11 12:55:00

前缀索引索引值

2011-08-17 20:48:25

索引建立语句非聚集索引唯一索引

2012-12-24 13:54:13

WebjQuery前端

2012-05-07 08:47:25

Erlang

2009-04-28 19:42:44

Linux系统FTP搜索
点赞
收藏

51CTO技术栈公众号