Lucene Index 考察(4)

##概要
インデックスと関連する二つのコマンド（option）を検証します。

* expungeDeletes
* prepareCommit

##expungeDeletes
Lucene Index 考察(2)で、deleteでドキュメントを削除してもインデックスに残され、その削除フラグだけ別途保存していることを確認していました。
ドキュメントが実際削除されるのはoptimizeコマンドでセグメントファイルをひとつにまとめる際でした。

commit時にexpungeDeletesをtrueに指定すると、deleteでドキュメントをインデックスから完全に削除してくれます(しかもoptimizeより軽く)。
これでインデックスサイズの削減と検索時メモリ消費を抑えることができます。もう一つのメリットは適切なスコアを計算してくれるようになることです。
その理由は、インデックスに削除済みドキュメントが残っていると、不本意にidf値計算のファクタであるdocFreqとmaxDocに削除済みドキュメントも含まれてしまうからです。

実際確認してみましょう。

* 1segmentに2document登録し、その一つを削除してみます。

まず、2documentを登録します。
登録用XMLファイル test-2add.xml

```
$ cat test-2add.xml
<add>
<doc>
  <field name="id">USD</field>
  <field name="name">One Dollar</field>
  <field name="manu">Bank of America</field>
  <field name="manu_id_s">boa</field>
  <field name="cat">currency</field>
  <field name="cat">USD</field>
  <field name="features">Coins and notes</field>
  <field name="price_c">1,USD</field>
  <field name="inStock">true</field>
</doc>
<doc>
  <field name="id">EUR</field>
  <field name="name">One Euro</field>
  <field name="manu">European Union</field>
  <field name="manu_id_s">eu</field>
  <field name="cat">currency</field>
  <field name="cat">EUR</field>
  <field name="features">Coins and notes</field>
  <field name="price_c">1,EUR</field>
  <field name="inStock">true</field>
</doc>
</add>
```
* dataディレクトリを削除し、solr起動

```
$ rm -Rf $SOLR_HOME/collection1/data
$ java -jar start.jar
```
* add

```
$ curl http://localhost:8983/solr/collection1/update?commit=true -H "Content-Type: text/xml" --data-binary @test-2add.xml 
```

* dataディレクトリを確認  

```
$ ls -lRi $SOLR_HOME/collection1/data
total 0
30612265 drwxr-xr-x  15 mingchunzhao  staff  510  1 29 06:55 index
30612269 drwxr-xr-x   3 mingchunzhao  staff  102  1 29 06:55 tlog

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/index:
total 96
30612285 -rw-r--r--  1 mingchunzhao  staff   206  1 29 06:55 _0.fdt
30612281 -rw-r--r--  1 mingchunzhao  staff    63  1 29 06:55 _0.fdx
30612277 -rw-r--r--  1 mingchunzhao  staff  1211  1 29 06:55 _0.fnm
30612280 -rw-r--r--  1 mingchunzhao  staff    42  1 29 06:55 _0.nvd
30612283 -rw-r--r--  1 mingchunzhao  staff    81  1 29 06:55 _0.nvm
30612282 -rw-r--r--  1 mingchunzhao  staff   334  1 29 06:55 _0.si
30612278 -rw-r--r--  1 mingchunzhao  staff   121  1 29 06:55 _0_Lucene41_0.doc
30612279 -rw-r--r--  1 mingchunzhao  staff   112  1 29 06:55 _0_Lucene41_0.pos
30612284 -rw-r--r--  1 mingchunzhao  staff   895  1 29 06:55 _0_Lucene41_0.tim
30612286 -rw-r--r--  1 mingchunzhao  staff   375  1 29 06:55 _0_Lucene41_0.tip
30612288 -rw-r--r--  1 mingchunzhao  staff    36  1 29 06:55 segments.gen
30612287 -rw-r--r--  1 mingchunzhao  staff   131  1 29 06:55 segments_2
30612266 -rw-r--r--  1 mingchunzhao  staff     0  1 29 06:54 write.lock

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/tlog:
total 8
30612276 -rw-r--r--  1 mingchunzhao  staff  338  1 29 06:55 tlog.0000000000000000000
```
フィールド値を確認すると、1segmentに2document(USD,EUR)含まれています。

```
$ od -c $SOLR_HOME/collection1/data/index/_0.fdt
0000000    ? 327   l 027 030   L   u   c   e   n   e   4   1   S   t   o
0000020    r   e   d   F   i   e   l   d   s   D   a   t   a  \0  \0  \0
0000040  002 200 200 001 002  \0 002  \0  \n  \a 265   X 360   #  \0 003
0000060    U   S   D  \b  \n   O   n   e       D   o   l   l   a   r 030
0000100  017   B   a   n   k       o   f       A   m   e   r   i   c   a
0000120    ( 003   b   o   a   0  \b   c   u   r   r   e   n   c   y   0
0000140    1  \0 360 034   8 017   C   o   i   n   s       a   n   d    
0000160    n   o   t   e   s   P 005   1   ,   U   S   D   X 001   T   d
0000200  024 263   ( 246 177   @  \0  \0  \0 003   E   U   R  \b  \b   Z
0000220   \0   `   E   u   r   o 030 016 006  \0 350   p   e   a   n    
0000240    U   n   i   o   n   ( 002   e   u   V  \0   ?   E   U   R   V
0000260   \0 002   3   E   U   R   V  \0   P 246 201 240  \0  \0 300   (
0000300  223 350  \0  \0  \0  \0  \0  \0  \0  \0 222 337 245   ~ 
```
* id="USD"のdocumentを削除します。

削除用XMLファイル test-del1.xml

```
$ cat test-del1.xml
<delete>
  <id>USD</id>
</delete>
```
* 全件取得してみます。確かに2件ヒットします。

```
$ curl "http://localhost:8983/solr/collection1/select?q=*:*&fl=id,\[docid\]&indent=true"
<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">8</int>
  <lst name="params">
    <str name="fl">id,[docid]</str>
    <str name="indent">true</str>
    <str name="q">*:*</str>
  </lst>
</lst>
<result name="response" numFound="2" start="0">
  <doc>
    <str name="id">USD</str>
    <int name="[docid]">0</int></doc>
  <doc>
    <str name="id">EUR</str>
    <int name="[docid]">1</int></doc>
</result>
</response>
```
* delete

commitの属性としてexpungeDeletes=trueを指定します。

```
$ curl 'http://localhost:8983/solr/collection1/update?commit=true&expungeDeletes=true' -H "Content-Type: text/xml" --data-binary @test-del1.xml 
```
* 再度全件取得して見ると、USDが削除されています。

```
$ curl "http://localhost:8983/solr/collection1/select?q=*:*&fl=id,\[docid\]&indent=true"
<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">16</int>
  <lst name="params">
    <str name="fl">id,[docid]</str>
    <str name="indent">true</str>
    <str name="q">*:*</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <str name="id">EUR</str>
    <int name="[docid]">0</int></doc>
</result>
</response>
```
* dataディレクトリを確認  
Lucene Index 考察(2)で、expungeDeletes=trueを指定せずdeleteを行った場合、  
削除フラグを格納する .delファイルが追加されていましたが、今回は見当たりません。  
segment情報(segments.gen、segments_3)が変わりました。

```
$ ls -lRi $SOLR_HOME/collection1/data
total 0
30613015 drwxr-xr-x  15 mingchunzhao  staff  510  1 29 07:50 index
30613019 drwxr-xr-x   4 mingchunzhao  staff  136  1 29 07:50 tlog

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/index:
total 96
30613050 -rw-r--r--  1 mingchunzhao  staff   145  1 29 07:50 _1.fdt
30613046 -rw-r--r--  1 mingchunzhao  staff    63  1 29 07:50 _1.fdx
30613055 -rw-r--r--  1 mingchunzhao  staff  1211  1 29 07:50 _1.fnm
30613053 -rw-r--r--  1 mingchunzhao  staff    42  1 29 07:50 _1.nvd
30613048 -rw-r--r--  1 mingchunzhao  staff    81  1 29 07:50 _1.nvm
30613051 -rw-r--r--  1 mingchunzhao  staff   371  1 29 07:50 _1.si
30613049 -rw-r--r--  1 mingchunzhao  staff    83  1 29 07:50 _1_Lucene41_0.doc
30613047 -rw-r--r--  1 mingchunzhao  staff    80  1 29 07:50 _1_Lucene41_0.pos
30613052 -rw-r--r--  1 mingchunzhao  staff   749  1 29 07:50 _1_Lucene41_0.tim
30613054 -rw-r--r--  1 mingchunzhao  staff   375  1 29 07:50 _1_Lucene41_0.tip
30613057 -rw-r--r--  1 mingchunzhao  staff    36  1 29 07:50 segments.gen
30613056 -rw-r--r--  1 mingchunzhao  staff   131  1 29 07:50 segments_3
30613016 -rw-r--r--  1 mingchunzhao  staff     0  1 29 07:49 write.lock

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/tlog:
total 16
30613029 -rw-r--r--  1 mingchunzhao  staff  338  1 29 07:50 tlog.0000000000000000000
30613045 -rw-r--r--  1 mingchunzhao  staff   68  1 29 07:50 tlog.0000000000000000001
```
フィールド値を確認すると、segment_3に1 document(EUR)しか残っておらず、ドキュメントから完全に取り除いてくれたことがうかがえます。

```
$ od -c $SOLR_HOME/collection1/data/index/_1.fdt
0000000    ? 327   l 027 030   L   u   c   e   n   e   4   1   S   t   o
0000020    r   e   d   F   i   e   l   d   s   D   a   t   a  \0  \0  \0
0000040  002 200 200 001 002  \0 001  \n   V 360 002  \0 003   E   U   R
0000060   \b  \b   O   n   e       E   u   r   o 030 016 006  \0 360  \n
0000100    p   e   a   n       U   n   i   o   n   ( 002   e   u   0  \b
0000120    c   u   r   r   e   n   c   y   0   -  \0 360 025   8 017   C
0000140    o   i   n   s       a   n   d       n   o   t   e   s   P 005
0000160    1   ,   E   U   R   X 001   T   d 024 263   + 312 316 200  \0
0000200   \0 300   ( 223 350  \0  \0  \0  \0  \0  \0  \0  \0   k   ;   k
0000220    N                                    
```


##prepareCommit
Solrのexpert-level APIでLuceneのIndexWriter.prepareCommit()をコールしています。  
2フレーズcommitの中の第一フレーズのみ実施し、commit処理のほとんどをやってくれますが、インデックスから参照はできません。(commitは内部でprepareCommitを呼んでいます)  
prepareCommitが失敗した場合、rollbackできます。 
特に使う場面がないので運用で気にする必要はありませんが、一応確認してみます。

* まず、1document登録します。

登録用XMLファイル test-add1.xml

```
$ cat test-add1.xml
<add>
<doc>
  <field name="id">USD</field>
  <field name="name">One Dollar</field>
  <field name="manu">Bank of America</field>
  <field name="manu_id_s">boa</field>
  <field name="cat">currency</field>
  <field name="cat">USD</field>
  <field name="features">Coins and notes</field>
  <field name="price_c">1,USD</field>
  <field name="inStock">true</field>
</doc>
</add>
```
* dataディレクトリを削除し、solr起動

```
$ rm -Rf $SOLR_HOME/collection1/data
$ java -jar start.jar
```
* add

```
$ curl http://localhost:8983/solr/collection1/update -H "Content-Type: text/xml" --data-binary @test-add1.xml 
```
* dataディレクトリを確認

segment情報のみで関連ファイルはできていません(commitがまだなので)。

```
$ ls -lRi $SOLR_HOME/collection1/data
total 0
30666535 drwxr-xr-x  5 mingchunzhao  staff  170  1 29 13:48 index
30666539 drwxr-xr-x  3 mingchunzhao  staff  102  1 29 13:49 tlog

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/index:
total 16
30666538 -rw-r--r--  1 mingchunzhao  staff  36  1 29 13:48 segments.gen
30666537 -rw-r--r--  1 mingchunzhao  staff  53  1 29 13:48 segments_1
30666536 -rw-r--r--  1 mingchunzhao  staff   0  1 29 13:48 write.lock

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/tlog:
total 8
30666545 -rw-r--r--  1 mingchunzhao  staff  205  1 29 13:49 tlog.0000000000000000000
```
* prepareCommit

```
$ curl http://localhost:8983/solr/collection1/update?prepareCommit=true
```
* dataディレクトリを確認

通常commitすると、segments_1がsegments_2にインクリメントされますが、まだ変わっていません。
但し、その他各種ファイルはできあがっているように見えます。

```
$ ls -lRi $SOLR_HOME/collection1/data
total 0
30666535 drwxr-xr-x  15 mingchunzhao  staff  510  1 29 13:49 index
30666539 drwxr-xr-x   3 mingchunzhao  staff  102  1 29 13:49 tlog

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/index:
total 96
30666564 -rw-r--r--  1 mingchunzhao  staff   149  1 29 13:49 _0.fdt
30666560 -rw-r--r--  1 mingchunzhao  staff    63  1 29 13:49 _0.fdx
30666556 -rw-r--r--  1 mingchunzhao  staff  1211  1 29 13:49 _0.fnm
30666559 -rw-r--r--  1 mingchunzhao  staff    42  1 29 13:49 _0.nvd
30666562 -rw-r--r--  1 mingchunzhao  staff    81  1 29 13:49 _0.nvm
30666561 -rw-r--r--  1 mingchunzhao  staff   334  1 29 13:49 _0.si
30666557 -rw-r--r--  1 mingchunzhao  staff    83  1 29 13:49 _0_Lucene41_0.doc
30666558 -rw-r--r--  1 mingchunzhao  staff    82  1 29 13:49 _0_Lucene41_0.pos
30666563 -rw-r--r--  1 mingchunzhao  staff   771  1 29 13:49 _0_Lucene41_0.tim
30666565 -rw-r--r--  1 mingchunzhao  staff   375  1 29 13:49 _0_Lucene41_0.tip
30666538 -rw-r--r--  1 mingchunzhao  staff    36  1 29 13:48 segments.gen
30666537 -rw-r--r--  1 mingchunzhao  staff    53  1 29 13:48 segments_1
30666536 -rw-r--r--  1 mingchunzhao  staff     0  1 29 13:48 write.lock

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/tlog:
total 8
30666545 -rw-r--r--  1 mingchunzhao  staff  205  1 29 13:49 tlog.0000000000000000000
```
* フィールド値を確認すると、USDのドキュメントが格納されています。

```
$ od -c $SOLR_HOME/collection1/data/index/_0.fdt
0000000    ? 327   l 027 030   L   u   c   e   n   e   4   1   S   t   o
0000020    r   e   d   F   i   e   l   d   s   D   a   t   a  \0  \0  \0
0000040  002 200 200 001 002  \0 001  \n   Z 360   #  \0 003   U   S   D
0000060   \b  \n   O   n   e       D   o   l   l   a   r 030 017   B   a
0000100    n   k       o   f       A   m   e   r   i   c   a   ( 003   b
0000120    o   a   0  \b   c   u   r   r   e   n   c   y   0   1  \0 025
0000140  025   8 017   C   o   i   n   s       a   n   d       n   o   t
0000160    e   s   P 005   1   ,   U   S   D   X 001   T   d 024 263   -
0000200    L 236 300  \0  \0 300   ( 223 350  \0  \0  \0  \0  \0  \0  \0
0000220   \0 267 371   O 202          
```
* 問題はここで検索可能でしょうか？

全件取得をやってみます。
残念ながら検索にはヒットしません。

```
$ curl "http://localhost:8983/solr/collection1/select?q=*:*&fl=id,\[docid\]&indent=true"
<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">2</int>
  <lst name="params">
    <str name="fl">id,[docid]</str>
    <str name="indent">true</str>
    <str name="q">*:*</str>
  </lst>
</lst>
<result name="response" numFound="0" start="0">
</result>
</response>
```
* rollback

この時点でロールバック可能です。

```
$ curl http://localhost:8983/solr/collection1/update?rollback=true
```
* dataディレクトリを確認

各種ファイルが消えています。

```
$ ls -lRi $SOLR_HOME/collection1/data
total 0
30666535 drwxr-xr-x  5 mingchunzhao  staff  170  1 29 13:54 index
30666539 drwxr-xr-x  3 mingchunzhao  staff  102  1 29 13:49 tlog

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/index:
total 16
30666538 -rw-r--r--  1 mingchunzhao  staff  36  1 29 13:48 segments.gen
30666537 -rw-r--r--  1 mingchunzhao  staff  53  1 29 13:48 segments_1
30666536 -rw-r--r--  1 mingchunzhao  staff   0  1 29 13:48 write.lock

/Users/mingchunzhao/blog/solr-4.10.2/example/solr/collection1/data/tlog:
total 8
30666545 -rw-r--r--  1 mingchunzhao  staff  205  1 29 13:49 tlog.0000000000000000000

```

##次回

次回はインデックスに関係するSolrの各種パラメータを検証してみます。お楽しみに。