BLOGTIMES
2011/07/03

Solr のフィールドにHTMLを入れる

  solr 
このエントリーをはてなブックマークに追加

Solr のフィールドにタグを実体参照にした HTML をそのまま投入してみたら、ぽつぽつ登録できないドキュメントが出てしまって困りました。
ログを見るとこんな感じなので、どうやら のような実体参照の部分で引っかかっている模様。

2011/07/03 21:51:14 org.apache.solr.core.SolrCore execute 情報: [] webapp=/solr path=/update params={} status=500 QTime=0 2011/07/03 21:51:14 org.apache.solr.common.SolrException log 致命的: [com.ctc.wstx.exc.WstxLazyException] com.ctc.wstx.exc.WstxParsingException: Undeclared general entity "nbsp" at [row,col {unknown-source}]: [8,46] ・・・・・

よく考えたらSolrのXMLによるインターフェイス*1ValidなXMLしか受け付けないので、規定されている5種類の実体参照(&, <, >, ", ')以外は、XMLの規則に則って数値文字参照を使うか、DTDを書かなければ受け付けられないのは当たり前ですね。こういう事をあまりやる人はいないのか、ググってもいい解決方法が出てきませんでした。

元データの実体参照を解決していっても良いのですが、面倒なので Solr から外部の DTD を読み込む方法を調べることにしました。

解決方法

結論から述べると、W3CにあるXHTML仕様*2ZIPファイルから、xhtml-lat1.ent、xhtml-special.ent、xhtml-symbol.entの3つのファイルを取り出し、Solrのワーキングディレクトリ(SolrのAdmin画面にアクセスしたときにcwdとして表示されている場所)に置いておきます。

Solr Admin 画面 - Solr のフィールドにHTMLを入れる

あとはPOSTするXMLに下記のようなDTDを書いてやればOKです

<!DOCTYPE doc [ <!ENTITY % HTMLlat1 PUBLIC "-//W3C//ENTITIES Latin 1 for XHTML//EN" "xhtml-lat1.ent"> %HTMLlat1; <!ENTITY % HTMLsymbol PUBLIC "-//W3C//ENTITIES Symbols for XHTML//EN" "xhtml-symbol.ent"> %HTMLsymbol; <!ENTITY % HTMLspecial PUBLIC "-//W3C//ENTITIES Special for XHTML//EN" "xhtml-special.ent"> %HTMLspecial; ]>

以下は個人的なメモです。

今回使ったサンプル

Solrのチュートリアルに使われているスキーマに対応するような下記のXMLを使います。

html-example.xml

<?xml version="1.0" encoding="UTF-8"?> <add> <doc> <field name="id">HTMLTEST</field> <field name="name">Test with some HTML entity characters</field> <field name="manu">CLES Project</field> <field name="cat">test</field> <field name="features">&lt;&gt;&amp;&nbsp;&copy;</field> <field name="price">0</field> </doc> </add>

そのままPOSTするとどうなるか

これをチュートリアルでも使われている post.jar で追加しようとするとこんな感じのエラーが出ます。

G:\apache-solr-3.3.0\example\exampledocs>java -jar post.jar html-example.xml SimplePostTool: version 1.3 SimplePostTool: POSTing files to http://localhost:8983/solr/update.. SimplePostTool: POSTing file html-example.xml SimplePostTool: FATAL: Solr returned an error #500 [com.ctc.wstx.exc.WstxLazyException] Undeclared general entity "nbsp" at [row,col {unknown-source}]: [8,46] [com.ctc.wstx.exc.WstxLazyException] com.ctc.wstx.exc.WstxParsingException: Undeclared general entity "nbsp" at [row,col {unknown-source}]: [8,46] at com.ctc.wstx.exc.WstxLazyException.throwLazily(WstxLazyException.java:45) at com.ctc.wstx.sr.StreamScanner.throwLazyError(StreamScanner.java:729) at com.ctc.wstx.sr.BasicStreamReader.safeFinishToken(BasicStreamReader.java:3659) at com.ctc.wstx.sr.BasicStreamReader.getText(BasicStreamReader.java:809) at org.apache.solr.handler.XMLLoader.readDoc(XMLLoader.java:287) at org.apache.solr.handler.XMLLoader.processUpdate(XMLLoader.java:146) at org.apache.solr.handler.XMLLoader.load(XMLLoader.java:77) at org.apache.solr.handler.ContentStreamHandlerBase.handleRequestBody(ContentStreamHandlerBase.java:67) at org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:129) at org.apache.solr.core.SolrCore.execute(SolrCore.java:1368) at org.apache.solr.servlet.SolrDispatchFilter.execute(SolrDispatchFilter.java:356) at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:252) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212) at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:399) at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766) at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450) at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at org.mortbay.jetty.Server.handle(Server.java:326) at org.mortbay.jetty.HttpConnection.handleR

インクルードするDTDファイルを探す

&nbsp;はXHTMLの仕様を見ると「A.2.1. Latin-1 characters」に含まれているようです。XHTMLの仕様のzipファイルを解凍すると xhtml1/DTD の中にお目当ての xhtml-lat1.ent があります。これを開いてみるとファイルの先頭に下記の記述があり、&nbsp;の定義とこのファイルの呼出方法が分かりました。

<!-- Portions (C) International Organization for Standardization 1986 Permission to copy in any form is granted for use with conforming SGML systems and applications as defined in ISO 8879, provided this notice is included in all copies. --> <!-- Character entity set. Typical invocation: <!ENTITY % HTMLlat1 PUBLIC "-//W3C//ENTITIES Latin 1 for XHTML//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent"> %HTMLlat1; --> <!ENTITY nbsp "&#160;"> <!-- no-break space = non-breaking space, U+00A0 ISOnum -->

XMLにDTD定義を追加する

上記に従ってXMLを下記のように書き換えます。

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE doc [ <!ENTITY % HTMLlat1 PUBLIC "-//W3C//ENTITIES Latin 1 for XHTML//EN" "xhtml-lat1.ent"> %HTMLlat1; <!ENTITY % HTMLsymbol PUBLIC "-//W3C//ENTITIES Symbols for XHTML//EN" "xhtml-symbol.ent"> %HTMLsymbol; <!ENTITY % HTMLspecial PUBLIC "-//W3C//ENTITIES Special for XHTML//EN" "xhtml-special.ent"> %HTMLspecial; ]> <add> <doc> <field name="id">HTMLTEST</field> <field name="name">Test with some HTML entity characters</field> <field name="manu">CLES Project</field> <field name="cat">test</field> <field name="features">&lt;&gt;&amp;&nbsp;&copy;</field> <field name="price">0</field> </doc> </add>

ここまでは良かったのですが、肝心の *.ent を何処に放り混んだらパーサーが読み込んでくれるか分かりません。
仕方がないので、このままXMLをPOSTしてみます。

G:\apache-solr-3.3.0\example\exampledocs>java -jar post.jar html-example.xml SimplePostTool: version 1.3 SimplePostTool: POSTing files to http://localhost:8983/solr/update.. SimplePostTool: POSTing file html-example.xml SimplePostTool: FATAL: Solr returned an error #400 (was java.io.FileNotFoundException) G:\apache-solr-3.3.0\example\xhtml-lat1.ent (??????????????????) at [row,col {unknown-source}]: [4,10]

上記のエラーメッセージで xhtml-lat1.ent を放り込む場所が明らかになったので、指示された場所にファイルを放り込んでやります。
その後、再度実行すると下記のようにエラーは出なくなくなります。

G:\apache-solr-3.3.0\example\exampledocs>java -jar post.jar html-example.xml SimplePostTool: version 1.3 SimplePostTool: POSTing files to http://localhost:8983/solr/update.. SimplePostTool: POSTing file html-example.xml SimplePostTool: COMMITting Solr index changes..

ちなみに一度読み込まれた外部DTDはキャッシュされているようで、*.entを削除してもSolrを再起動するまでファイルの追加は行えました。

最後に検索して内容を取り出してみる

Solrを検索してフィールドを取り出してみると、狙い通りの結果を取り出すことが出来ました。

<?xml version="1.0" encoding="UTF-8"?> <response> <lst name="responseHeader"> <int name="status">0</int> <int name="QTime">0</int> <lst name="params"> <str name="indent">on</str> <str name="start">0</str> <str name="q">id:HTMLTEST</str> <str name="version">2.2</str> <str name="rows">10</str> </lst> </lst> <result name="response" numFound="1" start="0"> <doc> <arr name="cat"><str>test</str></arr> <arr name="features"><str>&lt;&gt;&amp; ©</str></arr> <str name="id">HTMLTEST</str> <str name="manu">CLES Project</str> <str name="name">Test with some HTML entity characters</str> <float name="price">0.0</float> </doc> </result> </response>

大した事ではありませんが、以外と苦労しましたね。


トラックバックについて
Trackback URL:
お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/4306
Trackbacks
このエントリにトラックバックはありません
Comments
愛のあるツッコミをお気軽にどうぞ。[policy]
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントはありません
Comments Form

コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。

OpenID を使ってログインすることができます。

Identity URL: Yahoo! JAPAN IDでログイン