プラグインDMSFの検索エンジンをHyper Estraierへ替える » 履歴 » バージョン 7
Masanori Machii, 2011/10/21 17:29
1 | 1 | Masanori Machii | h1. プラグインDMSFの検索エンジンをHyper Estraierへ替える |
---|---|---|---|
2 | |||
3 | h2. DMSFとRedmineの関係 |
||
4 | |||
5 | 2 | Masanori Machii | DMSFはRedmineが標準で備える種々の文書管理を一つにまとめて置き換えようとしたものです.ユーザーインターフェイスは優れていますが,残念ながら検索エンジンにXapianを利用しており,そのままでは日本語に対応できません.そこで,Hyper Estraierへ置き換えるわけですが,改造はエンジンのみの置き換えで済むので,DMSFの基本的な構造は変わりません. |
6 | 1 | Masanori Machii | |
7 | その要点は次のとおりです. |
||
8 | |||
9 | bq. 注)$REDMINEは自動的に設定される環境編ではありません.ここでは便宜的に使います. |
||
10 | |||
11 | # {{fn(DMSFが管理する文書,ファイル名が同じであっても,インデックスは異なるよう,接頭辞が付いています.)}}はすべて $REDMINE/files/dnsf へ置かれる. |
||
12 | # インデックスファイルを作成するプロセスが定期的に動作し,それは {{fn($REDMINE/files へ置かれる,これは管理者が設定できるのですが,わかりやすくするため,推奨としました.)}}. |
||
13 | 3 | Masanori Machii | |
14 | 5 | Masanori Machii | 【例】"whitemine" というディレクトリにRedmineがインストールされている場合 |
15 | !ファイル保存フォルダ.png! |
||
16 | 4 | Masanori Machii | |
17 | 5 | Masanori Machii | !インデックスデータベース.png! |
18 | 4 | Masanori Machii | |
19 | これは,DMSFの設定画面にも現れています.またこの画面では,Xapianに由来する設定がありますが,それがHyper Estraierでは不要になります. |
||
20 | |||
21 | 5 | Masanori Machii | !Xapianの設定.png! |
22 | 1 | Masanori Machii | |
23 | ここでは,オリジナルを(ちょっと手を抜いた)次の方針で改造することにします. |
||
24 | |||
25 | 5 | Masanori Machii | # Web画面に "Xapian" 由来の設定などがあれば,それはそのままにし,削除しない. |
26 | # Web画面に Estraier に対応するものがあれば,それは "Estraier" へと修正する.(現バージョンではない) |
||
27 | # エラーメッセージなどに "Xapian" という文字列があれば,それは "Estraier" へと上書きする. |
||
28 | 1 | Masanori Machii | # ソースコード中 "Xapian" を呼び出す部分は削除する.(ロジックの変更) |
29 | 5 | Masanori Machii | # ソースコード中 "Xapian" という変数名がそのまま "Estraier" へと置き換えられる部分は "Estraier" へと修正する. |
30 | # ソースコード中 "Xapian" というラベル名称はそのまま利用する. |
||
31 | |||
32 | さて,変更するファイルは次の3つです. |
||
33 | |||
34 | * config/locales/ja.yml |
||
35 | * app/views/settings/_dmsf_settings.erb |
||
36 | * app/models/dmsf_file.rb |
||
37 | |||
38 | h2. config/locales/ja.ymlの修正 |
||
39 | |||
40 | 7 | Masanori Machii | コード中のラベルも含めて,Xapian から Estraier へと修正しています. |
41 | 5 | Masanori Machii | |
42 | <pre> |
||
43 | @@ -156,7 +156,7 @@ |
||
44 | :error_file_storage_directory_does_not_exist: "ファイル保存フォルダが存在せず作ることもできません" |
||
45 | :error_file_can_not_be_created: "ファイルを保存フォルダに作ることができません" |
||
46 | :error_wrong_zip_encoding: "Zip エンコーディングが正しくありません" |
||
47 | - :warning_xapian_not_available: "Xapian が利用できる状態になっていません" |
||
48 | 7 | Masanori Machii | + :warning_estraier_not_available: "Hyper Estraier が利用できる状態になっていません" |
49 | 5 | Masanori Machii | :menu_dmsf: "DMSF" |
50 | :label_physical_file_delete: "物理ファイルの削除" |
||
51 | 7 | Masanori Machii | :user_is_not_project_member: "あなたはプロジェクトのメンバーではありません" |
52 | 5 | Masanori Machii | </pre> |
53 | 1 | Masanori Machii | |
54 | 5 | Masanori Machii | h2. app/views/settings/_dmsf_settings.erb |
55 | 1 | Masanori Machii | |
56 | 7 | Masanori Machii | ライブラリ名称を xapian から estraier に変更します.加えて,先の ya.yml に対応する警告のラベルと一致させます. |
57 | 抽出方針(Stem)に相当する部分も,文字列を xapian から estraier へと修正していますが,Xapian は機能しませんので,これはおまけと考えて下さい. |
||
58 | 5 | Masanori Machii | |
59 | 7 | Masanori Machii | |
60 | 5 | Masanori Machii | <pre> |
61 | 7 | Masanori Machii | @@ -75,22 +75,22 @@ |
62 | 1 | Masanori Machii | |
63 | <hr /> |
||
64 | <% begin |
||
65 | - require 'xapian' |
||
66 | 7 | Masanori Machii | - xapian_disabled = false |
67 | 1 | Masanori Machii | + require 'estraier' |
68 | 7 | Masanori Machii | + estraier_disabled = false |
69 | 1 | Masanori Machii | rescue LoadError %> |
70 | 7 | Masanori Machii | - <p class="warning"><%= l(:warning_xapian_not_available) %></p> |
71 | -<% xapian_disabled = true |
||
72 | + <p class="warning"><%= l(:warning_estraier_not_available) %></p> |
||
73 | +<% estraier_disabled = true |
||
74 | end %> |
||
75 | |||
76 | <p> |
||
77 | <%=content_tag(:label, l(:label_index_database) + ":") %> |
||
78 | - <%=text_field_tag 'settings[dmsf_index_database]', @settings['dmsf_index_database'], :disabled => xapian_disabled, :size=>50 %><br/> |
||
79 | + <%=text_field_tag 'settings[dmsf_index_database]', @settings['dmsf_index_database'], :disabled => estraier_disabled, :size=>50 %><br/> |
||
80 | (<%=l(:label_default)%>: <%="#{RAILS_ROOT}/files/dmsf_index"%>) |
||
81 | </p> |
||
82 | |||
83 | <p> |
||
84 | <%=content_tag(:label, l(:label_stemming_language) + ":") %> |
||
85 | - <%=text_field_tag 'settings[dmsf_stemming_lang]', @settings['dmsf_stemming_lang'], :disabled => xapian_disabled %><br/> |
||
86 | + <%=text_field_tag 'settings[dmsf_stemming_lang]', @settings['dmsf_stemming_lang'], :disabled => estraier_disabled %><br/> |
||
87 | (<%=l(:label_default)%>: english )<br/> |
||
88 | <br/> |
||
89 | <%=l(:note_possible_values)%>: danish dutch english finnish french german german2 hungarian italian kraaij_pohlmann lovins norwegian porter portuguese romanian russian spanish swedish turkish (<%=l(:note_pass_none_to_disable_stemming)%>) |
||
90 | @@ -98,9 +98,9 @@ |
||
91 | |||
92 | <p> |
||
93 | <%=content_tag(:label, l(:label_stem_strategy) + ":")%> |
||
94 | - <%=radio_button_tag 'settings[dmsf_stemming_strategy]', 'STEM_NONE', @settings['dmsf_stemming_strategy'] == 'STEM_NONE', :disabled => xapian_disabled, :checked=>true %> <%=l(:option_stem_none)%><br> |
||
95 | - <%=radio_button_tag 'settings[dmsf_stemming_strategy]', 'STEM_SOME', @settings['dmsf_stemming_strategy'] == 'STEM_SOME', :disabled => xapian_disabled %> <%=l(:option_stem_some)%><br> |
||
96 | - <%=radio_button_tag 'settings[dmsf_stemming_strategy]', 'STEM_ALL', @settings['dmsf_stemming_strategy'] == 'STEM_ALL', :disabled => xapian_disabled %> <%=l(:option_stem_all)%><br> |
||
97 | + <%=radio_button_tag 'settings[dmsf_stemming_strategy]', 'STEM_NONE', @settings['dmsf_stemming_strategy'] == 'STEM_NONE', :disabled => estraier_disabled, :checked=>true %> <%=l(:option_stem_none)%><br> |
||
98 | + <%=radio_button_tag 'settings[dmsf_stemming_strategy]', 'STEM_SOME', @settings['dmsf_stemming_strategy'] == 'STEM_SOME', :disabled => estraier_disabled %> <%=l(:option_stem_some)%><br> |
||
99 | + <%=radio_button_tag 'settings[dmsf_stemming_strategy]', 'STEM_ALL', @settings['dmsf_stemming_strategy'] == 'STEM_ALL', :disabled => estraier_disabled %> <%=l(:option_stem_all)%><br> |
||
100 | <br/> |
||
101 | <%=l(:label_stemming_description)%>: |
||
102 | <br> |
||
103 | 1 | Masanori Machii | </pre> |
104 | 5 | Masanori Machii | |
105 | 1 | Masanori Machii | |
106 | h2. app/models/dmsf_file.rb |
||
107 | |||
108 | 検索機能本体の修正をします.主な修正の要点は次のとおりです. |
||
109 | |||
110 | XapianではなくてEstraier を呼び出します.呼び出し時のエラー処理はXapianと同様です. |
||
111 | 7 | Masanori Machii | エラーや警告のメッセージも, Estraier のそれへと修正します. |
112 | 1 | Masanori Machii | インデックスデータベースへのアクセスメソッドは,Xapianとは大幅に異なりますので,ざっくりと削除し,上書きします. |
113 | 7 | Masanori Machii | |
114 | まず,コードの冒頭には,ライブラリの存在の有無によるエラー処理があります. |
||
115 | |||
116 | <pre> |
||
117 | @@ -17,11 +17,11 @@ |
||
118 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
119 | |||
120 | begin |
||
121 | - require 'xapian' |
||
122 | - $xapian_bindings_available = true |
||
123 | + require 'estraier' |
||
124 | + $estraier_bindings_available = true |
||
125 | rescue LoadError |
||
126 | - Rails.logger.info "REDMAIN_XAPIAN ERROR: No Ruby bindings for Xapian installed !!. PLEASE install Xapian search engine interface for Ruby." |
||
127 | - $xapian_bindings_available = false |
||
128 | + Rails.logger.info "REDMAIN_ESTRAIER ERROR: No Ruby bindings for Estraier installed !!. PLEASE install Hyper Estraier search engine interface for Ruby." |
||
129 | + $estraier_bindings_available = false |
||
130 | end |
||
131 | |||
132 | </pre> |
||
133 | |||
134 | 次に,インデックスデータベースへのアクセスについて,エラー処理があります. |
||
135 | |||
136 | <pre> |
||
137 | @@ -260,46 +260,37 @@ |
||
138 | end |
||
139 | end |
||
140 | |||
141 | - if !options[:titles_only] && $xapian_bindings_available |
||
142 | + if !options[:titles_only] && $estraier_bindings_available |
||
143 | database = nil |
||
144 | begin |
||
145 | - database = Xapian::Database.new(Setting.plugin_redmine_dmsf["dmsf_index_database"].strip) |
||
146 | + database = Estraier::Database::new |
||
147 | + database.open(Setting.plugin_redmine_dmsf["dmsf_index_database"].strip, Estraier::Database::DBREADER) |
||
148 | rescue |
||
149 | - Rails.logger.warn "REDMAIN_XAPIAN ERROR: Xapian database is not properly set or initiated or is corrupted." |
||
150 | + Rails.logger.warn "REDMAIN_ESTRAIER ERROR: Estraier database is not properly set or initiated or is corrupted." |
||
151 | end |
||
152 | </pre> |
||
153 | |||
154 | |||
155 | database.nil 以下は大幅に構造が異なりますので,ざっくりと入れ替えましょう. |
||
156 | |||
157 | <pre> |
||
158 | unless database.nil? |
||
159 | - enquire = Xapian::Enquire.new(database) |
||
160 | + # create a search condition object |
||
161 | + cond = Estraier::Condition::new |
||
162 | |||
163 | - queryString = tokens.join(' ') |
||
164 | - qp = Xapian::QueryParser.new() |
||
165 | - stemmer = Xapian::Stem.new(Setting.plugin_redmine_dmsf['dmsf_stemming_lang'].strip) |
||
166 | - qp.stemmer = stemmer |
||
167 | - qp.database = database |
||
168 | - |
||
169 | - case Setting.plugin_redmine_dmsf['dmsf_stemming_strategy'].strip |
||
170 | - when "STEM_NONE" then qp.stemming_strategy = Xapian::QueryParser::STEM_NONE |
||
171 | - when "STEM_SOME" then qp.stemming_strategy = Xapian::QueryParser::STEM_SOME |
||
172 | - when "STEM_ALL" then qp.stemming_strategy = Xapian::QueryParser::STEM_ALL |
||
173 | - end |
||
174 | - |
||
175 | - if options[:all_words] |
||
176 | - qp.default_op = Xapian::Query::OP_AND |
||
177 | - else |
||
178 | - qp.default_op = Xapian::Query::OP_OR |
||
179 | - end |
||
180 | - |
||
181 | - query = qp.parse_query(queryString) |
||
182 | - |
||
183 | - enquire.query = query |
||
184 | - matchset = enquire.mset(0, 1000) |
||
185 | - |
||
186 | - unless matchset.nil? |
||
187 | - matchset.matches.each {|m| |
||
188 | - docdata = m.document.data{url} |
||
189 | - dochash = Hash[*docdata.scan(/(url|sample|modtime|type|size)=\/?([^\n\]]+)/).flatten] |
||
190 | - filename = dochash["url"] |
||
191 | - if !filename.nil? |
||
192 | + # set the search phrase to the search condition object |
||
193 | + queryString = tokens.join(options[:all_words] ? ' AND ': ' OR ') |
||
194 | + cond.set_phrase(queryString ) |
||
195 | + |
||
196 | + # get the result of search |
||
197 | + result = database.search(cond) |
||
198 | + |
||
199 | + if result |
||
200 | + # for each document in the result |
||
201 | + dnum = result.doc_num |
||
202 | + for i in 0...dnum |
||
203 | + # retrieve the document object |
||
204 | + doc = database.get_doc(result.get_doc_id(i), 0) |
||
205 | + next unless doc |
||
206 | + # display attributes |
||
207 | + uri = doc.attr("@uri") |
||
208 | + if uri |
||
209 | + filename = uri.sub(/.*\//, '') |
||
210 | dmsf_attrs = filename.split("_") |
||
211 | next if dmsf_attrs[1].blank? |
||
212 | next unless results.select{|f| f.id.to_s == dmsf_attrs[1]}.empty? |
||
213 | </pre> |
||
214 | |||
215 | 最後にインデックスデータベースを閉じて終了です. |
||
216 | |||
217 | <pre> |
||
218 | |||
219 | @@ -331,9 +322,14 @@ |
||
220 | end |
||
221 | end |
||
222 | end |
||
223 | - } |
||
224 | end |
||
225 | end |
||
226 | + |
||
227 | + # close the database |
||
228 | + unless database.close |
||
229 | + Rails.logger.warn(database.err_msg(database.error)) |
||
230 | + end |
||
231 | + end # unless database.nil? |
||
232 | end |
||
233 | |||
234 | [results, results_count] |
||
235 | </pre> |
||
236 | |||
237 | 修正は以上です. |