CLOVER🍀

That was when it all began.

LuceneのClassic QueryParserを使ってみる

LuceneのClassic QueryParserを、ちょっと勉強しようということで。

今回は、それなりにデータを入れてインデックスを作ろうと思ったので、こちらから住所データをダウンロードしてきました。

住所.jp
http://jusyo.jp/csv/new.php

データの仕様
http://jusyo.jp/csv/document.html

全フィールドは不要だと思うので、要りそうな分だけインデックスに取り込む形で利用します。使ったのは、全国版ですね。

では、まずはプログラムを。データをインデックスに登録して、Queryを投げられるところまでの環境を作るのが目的なので、プログラムの説明はあんまりしません。

build.sbt

name := "lucene-classic-query-parser-example"

version := "0.0.1-SNAPSHOT"

scalaVersion := "2.10.2"

organization := "littlewings"

libraryDependencies ++= Seq(
  "org.apache.lucene" % "lucene-core" % "4.3.1",
  "org.apache.lucene" % "lucene-analyzers-kuromoji" % "4.3.1",
  "org.apache.lucene" % "lucene-queryparser" % "4.3.1"
)

libraryDependencies += "net.sf.opencsv" % "opencsv" % "2.3"

しれっとLucene 4.3.1。

住所データはCSVファイルなので、解析にはopencsvを利用しました。

ここから先は、単一のScalaファイルです。

import文。
src/main/scala/LuceneQueryParseExample.scala

import scala.collection.JavaConverters._
import scala.util.{Failure, Success, Try}

import java.nio.charset.Charset
import java.nio.file.{Files, Paths}

import org.apache.lucene.analysis.ja.JapaneseAnalyzer
import org.apache.lucene.document.{Document, Field, StringField, TextField}
import org.apache.lucene.index.{DirectoryReader, IndexWriter, IndexWriterConfig}
import org.apache.lucene.queryparser.classic.QueryParser
import org.apache.lucene.search.{IndexSearcher, Query}
import org.apache.lucene.store.{Directory, RAMDirectory}
import org.apache.lucene.util.Version

import au.com.bytecode.opencsv.CSVReader

import LuceneQueryParserExample.CloseableWrapper

最後のimport文は、自作のImplicit Classです。

メインクラスとImplicit Class。

object LuceneQueryParserExample {
  def main(args: Array[String]): Unit = {
    val indexer = new AddressIndexer("zenkoku.csv")
    indexer.execute()

    println()

    InteractiveQuery.queryWhile()
  }

  implicit class CloseableWrapper[A <: AutoCloseable](val underlying: A) extends AnyVal {
    def foreach(f: A => Unit): Unit =
      try {
        f(underlying)
      } finally {
        if (underlying != null) {
          underlying.close()
        }
      }
  }
}

AutoCloseableなクラスを、forで扱えるようにしました。
対象の住所CSVは、「zenkoku.csv」になっています。

LuceneのDirectoryを扱うための簡易オブジェクト。

object DirectoryRepository {
  val directory: Directory = new RAMDirectory

  def withDir[A](body: (Directory, Version) => A): A = {
    val version = Version.LUCENE_43
    body(directory, version)
  }
}

インデキシングを行うクラス。

class AddressIndexer(fileName: String) {
  def execute(): Unit = {
    println(s"インデックスへの登録を開始します。入力ファイル => $fileName...")

    for (reader <- new CSVReader(Files.newBufferedReader(Paths.get(fileName),
                                                         Charset.forName("Windows-31J")),
                                 ',',
                                 '"')) {
      DirectoryRepository.withDir { (directory, version) =>
        val config = new IndexWriterConfig(version, new JapaneseAnalyzer(version))
        for (writer <- new IndexWriter(directory, config)) {
          val count =
            Iterator
              .continually(reader.readNext)
              .takeWhile(_ != null)
              .foldLeft(0) { (acc, tokens) =>
                if (acc > 0 && acc % 10000 == 0) {
                  printf("%1$,3d件…%n", acc)
                }

                writer.addDocument(new Address(tokens).toDocument)
                acc + 1
            }

          printf("%1$,3d件、インデックスに登録しました%n", count)
        }
      }
    }
  }
}

CSVの内容を、Luceneのドキュメントに変換するためのクラス。

class Address(tokens: Array[String]) {
  def toDocument: Document = {
    val doc = new Document
    doc.add(stringField("addressCd", 0))
    doc.add(stringField("zipNo", 4))
    doc.add(textField("prefecture", 7))
    doc.add(textField("prefectureKana", 8))
    doc.add(textField("city", 9))
    doc.add(textField("cityKana", 10))
    doc.add(textField("town", 11))
    doc.add(textField("townKana", 12))
    doc.add(textField("azachome", 15))
    doc.add(textField("azachomeKana", 16))
    doc
  }
  private def stringField(name: String, index: Int): Field =
    new StringField(name, tokens(index), Field.Store.YES)

  private def textField(name: String, index: Int): Field =
    new TextField(name, tokens(index), Field.Store.YES)
}

見ての通り、全フィールドは使っていません。

インデキシング後に、LuceneのQueryを受け付けるためのプロンプトを表すクラス。

object InteractiveQuery {
  def queryWhile(): Unit = {
    println("Start Interactive Query")

    DirectoryRepository.withDir { (directory, version) =>
      def query(queryString: String): Option[Query] =
        Try {
          new QueryParser(version, "prefecture", new JapaneseAnalyzer(version))
            .parse(queryString)
        } match {
          case Success(q) => Some(q)
          case Failure(th) =>
            println(s"[ERROR] Invalid Query: $th")
            None
        }

      for (reader <- DirectoryReader.open(directory)) {
        val searcher = new IndexSearcher(reader)

        Iterator
          .continually(readLine("Lucene Query> "))
          .takeWhile(_ != "exit")
          .withFilter(l => l != "" && !l.endsWith("\\c"))
          .foreach { line =>
            query(line).foreach { q =>
              println(s"入力したクエリ => $q")

              val hits = searcher.search(q, null, 200000).scoreDocs
              
              printf("%1$,3d件、ヒットしました%n", hits.length)

              if (hits.length > 0) {
                val n = 10
                printf("最初の%1$,3d件を表示します%n", n)

                hits.take(n).foreach { h =>
                  val hitDoc = searcher.doc(h.doc)
                  println { s"Score,N[${h.score}:${h.doc}] : Doc => " +
                            hitDoc
                              .getFields
                              .asScala
                              .map(_.stringValue)
                              .mkString("  ", " | ", "")
                          }
                }
              }
            }
          }
      }
    }

    println("Exit Interactive Query")
  }
}

何も打たないか、「\c」で終わると入力を無視するようにしています。「exit」と打つと、プログラムを終了します。

では、プログラムを実行します。

> run
[info] Running LuceneQueryParserExample 
インデックスへの登録を開始します。入力ファイル => zenkoku.csv...
10,000件…
20,000件…
30,000件…
40,000件…
50,000件…
60,000件…
70,000件…
80,000件…
90,000件…
100,000件…
110,000件…
120,000件…
130,000件…
140,000件…
148,204件、インデックスに登録しました

Start Interactive Query
Lucene Query> 

とまあ、こんな感じであとは待ち状態になるので、ここからQueryParserで理解できる文字列を打ち込んでいきます。

例えば、「東京」と打ってみます。

Lucene Query> 東京
入力したクエリ => prefecture:東京
8,526件、ヒットしました
最初の 10件を表示します
Score,N[2.409595:42534] : Doc =>   100000000 | 100-0000 | 東京都 | トウキョウト | 千代田区 | チヨダク |  |   |  | 
Score,N[2.409595:42535] : Doc =>   102007200 | 102-0072 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42536] : Doc =>   104866000 | 104-8660 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42537] : Doc =>   102812800 | 102-8128 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42538] : Doc =>   102812300 | 102-8123 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42539] : Doc =>   102812200 | 102-8122 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42540] : Doc =>   102812000 | 102-8120 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42541] : Doc =>   102811700 | 102-8117 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42542] : Doc =>   102811200 | 102-8112 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42543] : Doc =>   102810500 | 102-8105 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 

ヒットした件数と、入力したクエリの解析結果、そしてヒットしたデータのうち最初の10件のLuceneのスコアとドキュメントNo、ヒットしたデータが表示されます。

Classic QueryParser

Classic QueryParserで使える構文は、以下に記載があります。

Classic QueryParser Syntax: Overview of the Classic QueryParser's syntax and features.
http://lucene.apache.org/core/4_3_1/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description

なお、今回のQueryParserは

new QueryParser(version, "prefecture", new JapaneseAnalyzer(version))
  .parse(queryString)

と「prefecture」フィールドとデフォルトフィールドに、AnalyzerをKuromojiのJapaneseAnalyzerを使用しています。

基本的には、これに従って順次進めていく感じです。

TermQuery

最も基本的なクエリだと思います。単純なTermと、ダブルクォートで囲ったフレーズをサポートします。

単純なパターン。

Lucene Query> 東京

クエリの評価結果。

入力したクエリ => prefecture:東京

検索結果。

8,526件、ヒットしました
最初の 10件を表示します
Score,N[2.409595:42534] : Doc =>   100000000 | 100-0000 | 東京都 | トウキョウト | 千代田区 | チヨダク |  |   |  | 
Score,N[2.409595:42535] : Doc =>   102007200 | 102-0072 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42536] : Doc =>   104866000 | 104-8660 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42537] : Doc =>   102812800 | 102-8128 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42538] : Doc =>   102812300 | 102-8123 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42539] : Doc =>   102812200 | 102-8122 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42540] : Doc =>   102812000 | 102-8120 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42541] : Doc =>   102811700 | 102-8117 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42542] : Doc =>   102811200 | 102-8112 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42543] : Doc =>   102810500 | 102-8105 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 

では、ここで入力を「東京都」としてみます。

Lucene Query> 東京都

クエリの評価結果

入力したクエリ => prefecture:東京 prefecture:都

「東京」と「都」に分解されます。

8,526件、ヒットしました
最初の 10件を表示します
Score,N[3.407682:42534] : Doc =>   100000000 | 100-0000 | 東京都 | トウキョウト | 千代田区 | チヨダク |  |   |  | 
Score,N[3.407682:42535] : Doc =>   102007200 | 102-0072 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42536] : Doc =>   104866000 | 104-8660 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42537] : Doc =>   102812800 | 102-8128 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42538] : Doc =>   102812300 | 102-8123 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42539] : Doc =>   102812200 | 102-8122 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42540] : Doc =>   102812000 | 102-8120 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42541] : Doc =>   102811700 | 102-8117 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42542] : Doc =>   102811200 | 102-8112 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[3.407682:42543] : Doc =>   102810500 | 102-8105 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  |

今度は、「"東京都"」と入力してみます。こちらがフレーズを使った方です。

Lucene Query> "東京都"

クエリの評価結果が変わります。

入力したクエリ => prefecture:"東京 都"

検索結果の件数は変わりませんが、検索時のスコアが上昇します。

8,526件、ヒットしました
最初の 10件を表示します
Score,N[4.81919:42534] : Doc =>   100000000 | 100-0000 | 東京都 | トウキョウト | 千代田区 | チヨダク |  |   |  | 
Score,N[4.81919:42535] : Doc =>   102007200 | 102-0072 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42536] : Doc =>   104866000 | 104-8660 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42537] : Doc =>   102812800 | 102-8128 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42538] : Doc =>   102812300 | 102-8123 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42539] : Doc =>   102812200 | 102-8122 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42540] : Doc =>   102812000 | 102-8120 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42541] : Doc =>   102811700 | 102-8117 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42542] : Doc =>   102811200 | 102-8112 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[4.81919:42543] : Doc =>   102810500 | 102-8105 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 

フレーズ検索の場合は、指定した単語が連続で表れる必要があるので、

## 普通の検索
Lucene Query> 東京京都
入力したクエリ => prefecture:東京 prefecture:京都
16,070件、ヒットしました
最初の 10件を表示します
Score,N[0.8925773:94292] : Doc =>   603000000 | 603-0000 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク |  |   |  | 
Score,N[0.8925773:94293] : Doc =>   603813600 | 603-8136 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 出雲路神楽町 | イズモジカグラチョウ |  | 
Score,N[0.8925773:94294] : Doc =>   603813400 | 603-8134 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 出雲路立テ本町 | イズモジタテモトチョウ |  | 
Score,N[0.8925773:94295] : Doc =>   603813500 | 603-8135 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 出雲路俵町 | イズモジタワラチョウ |  | 
Score,N[0.8925773:94296] : Doc =>   603813300 | 603-8133 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 出雲路松ノ下町 | イズモジマツノシタチョウ |  | 
Score,N[0.8925773:94297] : Doc =>   603848100 | 603-8481 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 大北山鏡石町 | オオキタヤマカガミイシチョウ |  | 
Score,N[0.8925773:94298] : Doc =>   603848200 | 603-8482 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 大北山天神岡町 | オオキタヤマテンジンオカチョウ |  | 
Score,N[0.8925773:94299] : Doc =>   603848300 | 603-8483 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 大北山蓮ケ谷町 | オオキタヤマハスガダニチョウ |  | 
Score,N[0.8925773:94300] : Doc =>   603848800 | 603-8488 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 大北山長谷町 | オオキタヤマハセチョウ |  | 
Score,N[0.8925773:94301] : Doc =>   603848700 | 603-8487 | 京都府 | キョウトフ | 京都市北区 | キョウトシキタク | 大北山原谷乾町 | オオキタヤマハラダニイヌイチョウ |  | 

### フレーズ検索
Lucene Query> "東京京都"
入力したクエリ => prefecture:"東京 京都"
  0件、ヒットしました

通常の単語指定の方は、ヒットしているのが「東京都」と「京都府」の和になっているのに対して、フレーズ検索の方は「東京」と「京都」が連続で出現する都道府県はないため、0件になっています。

なお、昔のQueryParserは単語分割されるような文字列を渡した際にはフレーズとして扱っていたようですが、今は単にORに展開されるだけなんですね。

デフォルトでPhraseQueryを生成しなくなったQueryParserに注意(3.1)
http://lucene.jugem.jp/?eid=403

フィールド指定

クエリそのものではありませんが、QueryParserでは検索時にフィールド指定を行うことができます。何も指定しなかった場合は、QueryParser生成時に指定したデフォルトのフィールド(今回の場合は「prefecture(都道府県)」)が使用されます。

フィールド指定は、「フィールド名:」で行います。

cityフィールドを指定

Lucene Query> city:六本木

クエリの評価結果。

入力したクエリ => (city:六 city:六本木) city:本木

結果。

569件、ヒットしました
最初の 10件を表示します
Score,N[8.0486555:45584] : Doc =>   106003200 | 106-0032 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ |  | 
Score,N[8.0486555:45585] : Doc =>   106609000 | 106-6090 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー  | イズミガーデンタワー 
Score,N[8.0486555:45586] : Doc =>   106600100 | 106-6001 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 1階 | イズミガーデンタワー 01カイ
Score,N[8.0486555:45587] : Doc =>   106600200 | 106-6002 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 2階 | イズミガーデンタワー 02カイ
Score,N[8.0486555:45588] : Doc =>   106600300 | 106-6003 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 3階 | イズミガーデンタワー 03カイ
Score,N[8.0486555:45589] : Doc =>   106600400 | 106-6004 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 4階 | イズミガーデンタワー 04カイ
Score,N[8.0486555:45590] : Doc =>   106600500 | 106-6005 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 5階 | イズミガーデンタワー 05カイ
Score,N[8.0486555:45591] : Doc =>   106600600 | 106-6006 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 6階 | イズミガーデンタワー 06カイ
Score,N[8.0486555:45592] : Doc =>   106600700 | 106-6007 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 7階 | イズミガーデンタワー 07カイ
Score,N[8.0486555:45593] : Doc =>   106600800 | 106-6008 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 8階 | イズミガーデンタワー 08カイ

フレーズ検索でやる場合は、こんな指定方法で。

Lucene Query> town:"六本木"
入力したクエリ => town:"(六 六本木) 本木"
135件、ヒットしました
最初の 10件を表示します
Score,N[13.904535:45584] : Doc =>   106003200 | 106-0032 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ |  | 
Score,N[13.904535:45585] : Doc =>   106609000 | 106-6090 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー  | イズミガーデンタワー 
Score,N[13.904535:45586] : Doc =>   106600100 | 106-6001 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 1階 | イズミガーデンタワー 01カイ
Score,N[13.904535:45587] : Doc =>   106600200 | 106-6002 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 2階 | イズミガーデンタワー 02カイ
Score,N[13.904535:45588] : Doc =>   106600300 | 106-6003 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 3階 | イズミガーデンタワー 03カイ
Score,N[13.904535:45589] : Doc =>   106600400 | 106-6004 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 4階 | イズミガーデンタワー 04カイ
Score,N[13.904535:45590] : Doc =>   106600500 | 106-6005 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 5階 | イズミガーデンタワー 05カイ
Score,N[13.904535:45591] : Doc =>   106600600 | 106-6006 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 6階 | イズミガーデンタワー 06カイ
Score,N[13.904535:45592] : Doc =>   106600700 | 106-6007 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 7階 | イズミガーデンタワー 07カイ
Score,N[13.904535:45593] : Doc =>   106600800 | 106-6008 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 8階 | イズミガーデンタワー 08カイ

ワイルドカード検索(Wildcard Searches)

「?」と「*」を使った、ワイルドカード検索です。「?」は任意の1文字で、「*」は複数の文字にマッチします。

まずは、「?」から

Lucene Query> town:六?木

クエリの評価結果。

入力したクエリ => town:六?木

検索結果。

138件、ヒットしました
最初の 10件を表示します
Score,N[1.0:45584] : Doc =>   106003200 | 106-0032 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ |  | 
Score,N[1.0:45585] : Doc =>   106609000 | 106-6090 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー  | イズミガーデンタワー 
Score,N[1.0:45586] : Doc =>   106600100 | 106-6001 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 1階 | イズミガーデンタワー 01カイ
Score,N[1.0:45587] : Doc =>   106600200 | 106-6002 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 2階 | イズミガーデンタワー 02カイ
Score,N[1.0:45588] : Doc =>   106600300 | 106-6003 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 3階 | イズミガーデンタワー 03カイ
Score,N[1.0:45589] : Doc =>   106600400 | 106-6004 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 4階 | イズミガーデンタワー 04カイ
Score,N[1.0:45590] : Doc =>   106600500 | 106-6005 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 5階 | イズミガーデンタワー 05カイ
Score,N[1.0:45591] : Doc =>   106600600 | 106-6006 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 6階 | イズミガーデンタワー 06カイ
Score,N[1.0:45592] : Doc =>   106600700 | 106-6007 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 7階 | イズミガーデンタワー 07カイ
Score,N[1.0:45593] : Doc =>   106600800 | 106-6008 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 8階 | イズミガーデンタワー 08カイ

こんなのでもOK。

Lucene Query> town:六?木
入力したクエリ => town:六?木
138件、ヒットしました
最初の 10件を表示します

続いて、「*」を入力

Lucene Query> town:六本*

クエリの評価結果。

入力したクエリ => town:六本*

検索結果。

141件、ヒットしました
最初の 10件を表示します
Score,N[1.0:14635] : Doc =>   29420541 | 029-4205 | 岩手県 | イワテケン | 奥州市 | オウシュウシ | 前沢区六本松 | マエサワクロッポンマツ |  | 
Score,N[1.0:18119] : Doc =>   989063600 | 989-0636 | 宮城県 | ミヤギケン | 刈田郡七ヶ宿町 | カッタグンシチカシュクマチ | 六本杉 | ロッポンスギ |  | 
Score,N[1.0:45584] : Doc =>   106003200 | 106-0032 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ |  | 
Score,N[1.0:45585] : Doc =>   106609000 | 106-6090 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー  | イズミガーデンタワー 
Score,N[1.0:45586] : Doc =>   106600100 | 106-6001 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 1階 | イズミガーデンタワー 01カイ
Score,N[1.0:45587] : Doc =>   106600200 | 106-6002 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 2階 | イズミガーデンタワー 02カイ
Score,N[1.0:45588] : Doc =>   106600300 | 106-6003 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 3階 | イズミガーデンタワー 03カイ
Score,N[1.0:45589] : Doc =>   106600400 | 106-6004 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 4階 | イズミガーデンタワー 04カイ
Score,N[1.0:45590] : Doc =>   106600500 | 106-6005 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 5階 | イズミガーデンタワー 05カイ
Score,N[1.0:45591] : Doc =>   106600600 | 106-6006 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 6階 | イズミガーデンタワー 06カイ

こんなのもOKです。

Lucene Query> town:六*木
入力したクエリ => town:六*木
140件、ヒットしました
最初の 10件を表示します

Lucene Query> town:六*
入力したクエリ => town:六*
705件、ヒットしました
最初の 10件を表示します

ワイルドカードを使用すると、それ自体が単語として扱われるようですね。

Lucene Query> 東京都?
入力したクエリ => prefecture:東京都?
  0件、ヒットしました

Lucene Query> 東京都*
入力したクエリ => prefecture:東京都*
  0件、ヒットしました

Lucene Query> 東京都
入力したクエリ => prefecture:東京 prefecture:都
8,526件、ヒットしました
最初の 10件を表示します

ワイルドカードを使用した例では、「東京都」が形態素解析されていません。

よって、ワイルドカードで指定するのは、「Analyzerで分析後の単語」をワイルドカードで検索する、ということになるんでしょうね。

また、「?」や「*」は何らかの1文字以上のものにマッチする必要があるっぽいです。

制限事項としては、ワイルドカードで始まる条件指定や、ワイルドカードのみの指定は不可です。

Lucene Query> ?六
[ERROR] Invalid Query: org.apache.lucene.queryparser.classic.ParseException: Cannot parse '?六': '*' or '?' not allowed as first character in WildcardQuery

Lucene Query> *六
[ERROR] Invalid Query: org.apache.lucene.queryparser.classic.ParseException: Cannot parse '*六': '*' or '?' not allowed as first character in WildcardQuery

Lucene Query> ?
[ERROR] Invalid Query: org.apache.lucene.queryparser.classic.ParseException: Cannot parse '?': '*' or '?' not allowed as first character in WildcardQuery

Lucene Query> *
[ERROR] Invalid Query: org.apache.lucene.queryparser.classic.ParseException: Cannot parse '*': '*' or '?' not allowed as first character in WildcardQuery

フレーズ検索と一緒に使うと、キレイに無視されます。

Lucene Query> town:"六?木"
入力したクエリ => town:"六 木"
  1件、ヒットしました
最初の 10件を表示します
Score,N[8.056824:20522] : Doc =>   15006100 | 015-0061 | 秋田県 | アキタケン | 由利本荘市 | ユリホンジョウシ | 二十六木 | トドロキ |  | 
Lucene Query> town:"六*木"
入力したクエリ => town:"六 木"
  1件、ヒットしました
最初の 10件を表示します
Score,N[8.056824:20522] : Doc =>   15006100 | 015-0061 | 秋田県 | アキタケン | 由利本荘市 | ユリホンジョウシ | 二十六木 | トドロキ |  | 

まあ、「not within phrase queries」言ってますしね…。

正規表現検索(Regular Expression Searches)

「/」で囲うと、正規表現が利用可能になります。利用可能な正規表現は、RegExpクラスを見てくださいとのことです。

org.apache.lucene.util.automaton.RegExp
http://lucene.apache.org/core/4_3_1/core/org/apache/lucene/util/automaton/RegExp.html?is-external=true

試してみた感じ、

Lucene Query> /福(岡|島)/
入力したクエリ => prefecture:/福(岡|島)/
8,440件、ヒットしました
最初の 10件を表示します

Lucene Query> /福[岡島]/
入力したクエリ => prefecture:/福[岡島]/
8,440件、ヒットしました
最初の 10件を表示します

はヒットしますが

Lucene Query> /福(岡|島)県/
入力したクエリ => prefecture:/福(岡|島)県/
  0件、ヒットしました

Lucene Query> /福[岡島]県/
入力したクエリ => prefecture:/福[岡島]県/
  0件、ヒットしました

はヒットしないので、正規表現をマッチさせるのは、Analyzerで分解後の文字にマッチさせるようにする必要があるということなんでしょうね。

また、正規表現を使った場合は、ワイルドカードと同様、それ自体がひとつの単語として扱われているようですし。

あいまい検索(Fuzzy Searches)

「Damerau-Levenshtein Distance」に基づいた、あいまい検索が使えるそうな。って、「Damerau-Levenshtein Distance」自体は、わかってませんけど…。

あいまい検索は、「~」で指定して使います。

通常、

Lucene Query> town:六本木
入力したクエリ => (town:六 town:六本木) town:本木
569件、ヒットしました
最初の 10件を表示します
Score,N[8.0486555:45584] : Doc =>   106003200 | 106-0032 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ |  | 
Score,N[8.0486555:45585] : Doc =>   106609000 | 106-6090 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー  | イズミガーデンタワー 
Score,N[8.0486555:45586] : Doc =>   106600100 | 106-6001 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 1階 | イズミガーデンタワー 01カイ
Score,N[8.0486555:45587] : Doc =>   106600200 | 106-6002 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 2階 | イズミガーデンタワー 02カイ
Score,N[8.0486555:45588] : Doc =>   106600300 | 106-6003 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 3階 | イズミガーデンタワー 03カイ
Score,N[8.0486555:45589] : Doc =>   106600400 | 106-6004 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 4階 | イズミガーデンタワー 04カイ
Score,N[8.0486555:45590] : Doc =>   106600500 | 106-6005 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 5階 | イズミガーデンタワー 05カイ
Score,N[8.0486555:45591] : Doc =>   106600600 | 106-6006 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 6階 | イズミガーデンタワー 06カイ
Score,N[8.0486555:45592] : Doc =>   106600700 | 106-6007 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 7階 | イズミガーデンタワー 07カイ
Score,N[8.0486555:45593] : Doc =>   106600800 | 106-6008 | 東京都 | トウキョウト | 港区 | ミナトク | 六本木 | ロッポンギ | 泉ガーデンタワー 8階 | イズミガーデンタワー 08カイ

みたいな結果になるところが、あいまい検索を使用すると

入力したクエリ => town:六本木~2
344件、ヒットしました
最初の 10件を表示します
Score,N[2.7027605:94129] : Doc =>   529162700 | 529-1627 | 滋賀県 | シガケン | 蒲生郡日野町 | ガモウグンヒノチョウ | 仁本木 | ニホンギ |  | 
Score,N[2.238388:123586] : Doc =>   738004100 | 738-0041 | 広島県 | ヒロシマケン | 廿日市市 | ハツカイチシ | 六本松 | ロッポンマツ |  | 
Score,N[2.238388:134301] : Doc =>   810004400 | 810-0044 | 福岡県 | フクオカケン | 福岡市中央区 | フクオカシチュウオウク | 六本松 | ロッポンマツ |  | 
Score,N[2.238388:134302] : Doc =>   810857700 | 810-8577 | 福岡県 | フクオカケン | 福岡市中央区 | フクオカシチュウオウク | 六本松 | ロッポンマツ |  | 
Score,N[2.238388:134303] : Doc =>   810856000 | 810-8560 | 福岡県 | フクオカケン | 福岡市中央区 | フクオカシチュウオウク | 六本松 | ロッポンマツ |  | 
Score,N[2.173349:31935] : Doc =>   321127700 | 321-1277 | 栃木県 | トチギケン | 日光市 | ニッコウシ | 千本木 | センボンギ |  | 
Score,N[2.0630498:48016] : Doc =>   153005300 | 153-0053 | 東京都 | トウキョウト | 目黒区 | メグロク | 五本木 | ゴホンギ |  | 
Score,N[2.0630498:48017] : Doc =>   153856000 | 153-8560 | 東京都 | トウキョウト | 目黒区 | メグロク | 五本木 | ゴホンギ |  | 
Score,N[1.8947116:49606] : Doc =>   121005200 | 121-0052 | 東京都 | トウキョウト | 足立区 | アダチク | 六木 | ムツキ |  | 
Score,N[1.8947116:49607] : Doc =>   121850500 | 121-8505 | 東京都 | トウキョウト | 足立区 | アダチク | 六木 | ムツキ |  | 

みたいな結果になりました。今回は、なんか件数が減っていますが…。

あいまい検索も、入力した文字列全体が単語として扱われるみたいなので、その点の考慮は必要そうですね。

「~」の後ろには数値が指定できるようで、デフォルトの値は「2」です。

Lucene Query> town:六本木~
入力したクエリ => town:六本木~2

数値の範囲は、0から2までで指定可能だそうです。

現在は浮動小数点の値も使用可能だそうですが、非推奨でありLucene 5では削除される予定のようです。というか、使っても挙動がよくわかりません…。

Lucene Query> town:六本木~0.5
入力したクエリ => town:六本木~1
236件、ヒットしました
最初の 10件を表示します

Lucene Query> town:六本木~0.2
入力したクエリ => town:六本木~2
344件、ヒットしました
最初の 10件を表示します

どういう計算結果になってるんでしょう…。

Proximity Searches

「~」とフレーズ指定を組み合わせることで、Proximity Searchesというのができるそうな(日本語にすると??)。あいまい検索と同じく、「距離」ベースの考え方のようですが…。

ダブルクォートで囲った中で指定した単語(に似たもの?)が、指定のフィールドにn回以内登場することを条件として与える感じでしょうか。

Lucene Query> city:"福岡 東"~2

クエリの評価結果。

入力したクエリ => city:"福岡 東"~2

検索結果。

102件、ヒットしました
最初の 10件を表示します
Score,N[4.113635:133782] : Doc =>   813000000 | 813-0000 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク |  |   |  | 
Score,N[4.113635:133783] : Doc =>   813002500 | 813-0025 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 青葉 | アオバ |  | 
Score,N[4.113635:133784] : Doc =>   813858800 | 813-8588 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 青葉 | アオバ |  | 
Score,N[4.113635:133785] : Doc =>   811032200 | 811-0322 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 大岳 | オオタケ |  | 
Score,N[4.113635:133786] : Doc =>   812005200 | 812-0052 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 貝塚団地 | カイヅカダンチ |  | 
Score,N[4.113635:133787] : Doc =>   813001100 | 813-0011 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎 | カシイ |  | 
Score,N[4.113635:133788] : Doc =>   813001200 | 813-0012 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎駅東 | カシイエキヒガシ |  | 
Score,N[4.113635:133789] : Doc =>   813001300 | 813-0013 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎駅前 | カシイエキマエ |  | 
Score,N[4.113635:133790] : Doc =>   813001400 | 813-0014 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎台 | カシイダイ |  | 
Score,N[4.113635:133791] : Doc =>   813001500 | 813-0015 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎団地 | カシイダンチ |  | 

ダブルクォート内に単語がひとつしかない場合は、この指定は無視される感じがします。

Lucene Query> city:"福岡"~2
入力したクエリ => city:福岡
783件、ヒットしました
最初の 10件を表示します

クエリの評価結果から、「~2」がなくなっています…。

範囲検索(Range Searches)

」または「{}」を使用することで、範囲検索をすることができます。範囲の間は「TO」でつなぎます。

都合よく数値のフィールドを持っていなかったので、郵便番号の範囲で検索してみます。

「」を使用する方。

Lucene Query> zipNo:[813-0000 TO 813-0008]
入力したクエリ => zipNo:[813-0000 TO 813-0008]
  7件、ヒットしました
最初の 10件を表示します
Score,N[1.0:133782] : Doc =>   813000000 | 813-0000 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク |  |   |  | 
Score,N[1.0:133796] : Doc =>   813000300 | 813-0003 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香住ケ丘 | カスミガオカ |  | 
Score,N[1.0:133806] : Doc =>   813000200 | 813-0002 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 下原 | シモバル |  | 
Score,N[1.0:133820] : Doc =>   813000100 | 813-0001 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 唐原 | トウノハル |  | 
Score,N[1.0:133857] : Doc =>   813000400 | 813-0004 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 松香台 | マツカダイ |  | 
Score,N[1.0:133872] : Doc =>   813000500 | 813-0005 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 御島崎 | ミシマザキ |  | 
Score,N[1.0:136512] : Doc =>   813000800 | 813-0008 | 福岡県 | フクオカケン | 糟屋郡粕屋町 | カスヤグンカスヤマチ | 内橋 | ウチハシ |  | 

「{}」を使用する方。

Lucene Query> zipNo:{813-0000 TO 813-0008}
入力したクエリ => zipNo:{813-0000 TO 813-0008}
  5件、ヒットしました
最初の 10件を表示します
Score,N[1.0:133796] : Doc =>   813000300 | 813-0003 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香住ケ丘 | カスミガオカ |  | 
Score,N[1.0:133806] : Doc =>   813000200 | 813-0002 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 下原 | シモバル |  | 
Score,N[1.0:133820] : Doc =>   813000100 | 813-0001 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 唐原 | トウノハル |  | 
Score,N[1.0:133857] : Doc =>   813000400 | 813-0004 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 松香台 | マツカダイ |  | 
Score,N[1.0:133872] : Doc =>   813000500 | 813-0005 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 御島崎 | ミシマザキ |  | 

「[]」と「{}」の違いは、前者は下限と上限を含み、後者は下限と上限は含まない、です。

単語のブースト(Boosting a Term)

「^」を使用することで、単語の重要度を変えることができます。重要度の指定を行うと、検索結果のスコアに反映されます。指定方法は、「^」の後に続けて数値を記述します。

何も指定しないと重要度は「1」になります(そりゃそうだ?)。

たとえば、

Lucene Query> city:福岡 city:北九州

みたいな入力をすると(これはOR検索になっています)、

入力したクエリ => city:福岡 city:北九州

検索結果はこうなりますが

1,662件、ヒットしました
最初の 10件を表示します
Score,N[1.1136856:133782] : Doc =>   813000000 | 813-0000 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク |  |   |  | 
Score,N[1.1136856:133783] : Doc =>   813002500 | 813-0025 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 青葉 | アオバ |  | 
Score,N[1.1136856:133784] : Doc =>   813858800 | 813-8588 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 青葉 | アオバ |  | 
Score,N[1.1136856:133785] : Doc =>   811032200 | 811-0322 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 大岳 | オオタケ |  | 
Score,N[1.1136856:133786] : Doc =>   812005200 | 812-0052 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 貝塚団地 | カイヅカダンチ |  | 
Score,N[1.1136856:133787] : Doc =>   813001100 | 813-0011 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎 | カシイ |  | 
Score,N[1.1136856:133788] : Doc =>   813001200 | 813-0012 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎駅東 | カシイエキヒガシ |  | 
Score,N[1.1136856:133789] : Doc =>   813001300 | 813-0013 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎駅前 | カシイエキマエ |  | 
Score,N[1.1136856:133790] : Doc =>   813001400 | 813-0014 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎台 | カシイダイ |  | 
Score,N[1.1136856:133791] : Doc =>   813001500 | 813-0015 | 福岡県 | フクオカケン | 福岡市東区 | フクオカシヒガシク | 香椎団地 | カシイダンチ |  |

「北九州」の方の重要度を「5」にすると

Lucene Query> city:福岡 city:北九州^5
入力したクエリ => city:福岡 city:北九州^5.0

ヒットする件数は変わりませんが、結果の順番が変わります。

1,662件、ヒットしました
最初の 10件を表示します
Score,N[1.5007648:132903] : Doc =>   800000000 | 800-0000 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク |  |   |  | 
Score,N[1.5007648:132904] : Doc =>   800004500 | 800-0045 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 青葉台 | アオバダイ |  | 
Score,N[1.5007648:132905] : Doc =>   800010100 | 800-0101 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 伊川 | イカワ |  | 
Score,N[1.5007648:132906] : Doc =>   800004100 | 800-0041 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 泉ケ丘 | イズミガオカ |  | 
Score,N[1.5007648:132907] : Doc =>   800004800 | 800-0048 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 稲積 | イナヅミ |  | 
Score,N[1.5007648:132908] : Doc =>   800011100 | 800-0111 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 今津 | イマヅ |  | 
Score,N[1.5007648:132909] : Doc =>   800002600 | 800-0026 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 梅ノ木町 | ウメノキチョウ |  | 
Score,N[1.5007648:132910] : Doc =>   801086400 | 801-0864 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 老松町 | オイマツチョウ |  | 
Score,N[1.5007648:132911] : Doc =>   801088300 | 801-0883 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 大久保 | オオクボ |  | 
Score,N[1.5007648:132912] : Doc =>   801081100 | 801-0811 | 福岡県 | フクオカケン | 北九州市門司区 | キタキュウシュウシモジク | 大積 | オオツミ |  | 

「北九州」にヒットした方が、より上位に来ていますね。

重要度は正の数である必要がありますが、0.2のような小数点も指定可能です。

Boolean Operators

OR、AND、+、NOT、-の各種演算子を使用して、複数のクエリを結合することができます。なお、演算子は大文字で記述する必要があります。

OR

デフォルトの演算子で、指定したクエリのORを取ります…ってそのままですね。

例えば、「福岡」もしくは「東京」のいずれかを含むドキュメントを検索する場合は、こう書きます。

Lucene Query> 福岡 OR 東京
入力したクエリ => prefecture:福岡 prefecture:東京
12,662件、ヒットしました
最初の 10件を表示します

とはいえ、デフォルト演算子なので「OR」を書かなくても同じなわけですが。

Lucene Query> 福岡 東京
入力したクエリ => prefecture:福岡 prefecture:東京
12,662件、ヒットしました
最初の 10件を表示します
AND

指定したクエリの条件を、両方とも満たすように結合する演算子です。

たとえば、先の「福岡」と「東京」を指定した場合ですが

Lucene Query> 福岡 AND 東京
入力したクエリ => +prefecture:福岡 +prefecture:東京
  0件、ヒットしました

このANDをとっても当然ヒットするものはありません。

「赤羽」で。

Lucene Query> town:赤羽
入力したクエリ => town:赤羽
 22件、ヒットしました
最初の 10件を表示します
Score,N[9.770851:27443] : Doc =>   963782600 | 963-7826 | 福島県 | フクシマケン | 石川郡石川町 | イシカワグンイシカワマチ | 赤羽 | アカバネ |  | 
Score,N[9.770851:32126] : Doc =>   321440100 | 321-4401 | 栃木県 | トチギケン | 真岡市 | モオカシ | 赤羽 | アカバネ |  | 
Score,N[9.770851:32796] : Doc =>   321342600 | 321-3426 | 栃木県 | トチギケン | 芳賀郡市貝町 | ハガグンイチカイマチ | 赤羽 | アカバネ |  | 
Score,N[9.770851:32797] : Doc =>   321349800 | 321-3498 | 栃木県 | トチギケン | 芳賀郡市貝町 | ハガグンイチカイマチ | 赤羽 | アカバネ |  | 
Score,N[9.770851:32798] : Doc =>   321349700 | 321-3497 | 栃木県 | トチギケン | 芳賀郡市貝町 | ハガグンイチカイマチ | 赤羽 | アカバネ |  | 
Score,N[9.770851:49089] : Doc =>   115004500 | 115-0045 | 東京都 | トウキョウト | 北区 | キタク | 赤羽 | アカバネ |  | 
Score,N[9.770851:49090] : Doc =>   115871100 | 115-8711 | 東京都 | トウキョウト | 北区 | キタク | 赤羽 | アカバネ |  | 
Score,N[9.770851:58141] : Doc =>   959164100 | 959-1641 | 新潟県 | ニイガタケン | 五泉市 | ゴセンシ | 赤羽 | アカハネ |  | 
Score,N[9.770851:71420] : Doc =>   394000200 | 394-0002 | 長野県 | ナガノケン | 岡谷市 | オカヤシ | 赤羽 | アカハネ |  | 
Score,N[9.770851:72533] : Doc =>   399042400 | 399-0424 | 長野県 | ナガノケン | 上伊那郡辰野町 | カミイナグンタツノマチ | 赤羽 | アカハネ |  |

これを、東京に属するもので絞り込んでみます。

Lucene Query> 東京 AND town:赤羽
入力したクエリ => +prefecture:東京 +town:赤羽
 11件、ヒットしました
最初の 10件を表示します
Score,N[9.973317:49089] : Doc =>   115004500 | 115-0045 | 東京都 | トウキョウト | 北区 | キタク | 赤羽 | アカバネ |  | 
Score,N[9.973317:49090] : Doc =>   115871100 | 115-8711 | 東京都 | トウキョウト | 北区 | キタク | 赤羽 | アカバネ |  | 
Score,N[6.5649776:49091] : Doc =>   115005200 | 115-0052 | 東京都 | トウキョウト | 北区 | キタク | 赤羽北 | アカバネキタ |  | 
Score,N[6.5649776:49092] : Doc =>   115005300 | 115-0053 | 東京都 | トウキョウト | 北区 | キタク | 赤羽台 | アカバネダイ |  | 
Score,N[6.5649776:49093] : Doc =>   115852400 | 115-8524 | 東京都 | トウキョウト | 北区 | キタク | 赤羽台 | アカバネダイ |  | 
Score,N[6.5649776:49094] : Doc =>   115005500 | 115-0055 | 東京都 | トウキョウト | 北区 | キタク | 赤羽西 | アカバネニシ |  | 
Score,N[6.5649776:49095] : Doc =>   115851100 | 115-8511 | 東京都 | トウキョウト | 北区 | キタク | 赤羽西 | アカバネニシ |  | 
Score,N[6.5649776:49096] : Doc =>   115004400 | 115-0044 | 東京都 | トウキョウト | 北区 | キタク | 赤羽南 | アカバネミナミ |  | 
Score,N[6.5649776:49097] : Doc =>   115852900 | 115-8529 | 東京都 | トウキョウト | 北区 | キタク | 赤羽南 | アカバネミナミ |  | 
Score,N[6.5649776:49098] : Doc =>   115858500 | 115-8585 | 東京都 | トウキョウト | 北区 | キタク | 赤羽南 | アカバネミナミ |  | 

まあ、割と直感的ですよね。

+

「+」を前に置くことで、指定したクエリにマッチする結果を含むことを要求する演算子になります。

例えば、「東京 town:港」を指定すると両方のORになるのでこういう結果になりますが、

Lucene Query> 東京 town:港
入力したクエリ => prefecture:東京 town:港
8,590件、ヒットしました
最初の 10件を表示します
Score,N[3.9940016:4045] : Doc =>   97002100 | 097-0021 | 北海道 | ホッカイドウ | 稚内市 | ワッカナイシ | 港 | ミナト |  | 
Score,N[3.9940016:6105] : Doc =>   48060400 | 048-0604 | 北海道 | ホッカイドウ | 島牧郡島牧村 | シママキグンシママキムラ | 港 | ミナト |  | 
Score,N[3.9940016:15772] : Doc =>   983000100 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 1丁目 | 01チョウメ
Score,N[3.9940016:15773] : Doc =>   983000101 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 2丁目 | 02チョウメ
Score,N[3.9940016:15774] : Doc =>   983000102 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 3丁目 | 03チョウメ
Score,N[3.9940016:15775] : Doc =>   983000103 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 4丁目 | 04チョウメ
Score,N[3.9940016:15776] : Doc =>   985090100 | 985-0901 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 5丁目 | 05チョウメ
Score,N[3.9940016:15777] : Doc =>   983850200 | 983-8502 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト |  | 
Score,N[3.9940016:41220] : Doc =>   279002400 | 279-0024 | 千葉県 | チバケン | 浦安市 | ウラヤスシ | 港 | ミナト |  | 
Score,N[3.9940016:79921] : Doc =>   437162300 | 437-1623 | 静岡県 | シズオカケン | 御前崎市 | オマエザキシ | 港 | ミナト |  | 

東京に「+」を付けることで、東京都に絞り込めます。

Lucene Query> +東京 town:港
入力したクエリ => +prefecture:東京 town:港
8,526件、ヒットしました
最初の 10件を表示します
Score,N[0.4866236:42534] : Doc =>   100000000 | 100-0000 | 東京都 | トウキョウト | 千代田区 | チヨダク |  |   |  | 
Score,N[0.4866236:42535] : Doc =>   102007200 | 102-0072 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42536] : Doc =>   104866000 | 104-8660 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42537] : Doc =>   102812800 | 102-8128 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42538] : Doc =>   102812300 | 102-8123 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42539] : Doc =>   102812200 | 102-8122 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42540] : Doc =>   102812000 | 102-8120 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42541] : Doc =>   102811700 | 102-8117 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42542] : Doc =>   102811200 | 102-8112 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[0.4866236:42543] : Doc =>   102810500 | 102-8105 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 

フィールドの前に「+」を付けてもOKです。

Lucene Query> 東京 +town:港
入力したクエリ => prefecture:東京 +town:港
 64件、ヒットしました
最初の 10件を表示します
Score,N[3.9940016:4045] : Doc =>   97002100 | 097-0021 | 北海道 | ホッカイドウ | 稚内市 | ワッカナイシ | 港 | ミナト |  | 
Score,N[3.9940016:6105] : Doc =>   48060400 | 048-0604 | 北海道 | ホッカイドウ | 島牧郡島牧村 | シママキグンシママキムラ | 港 | ミナト |  | 
Score,N[3.9940016:15772] : Doc =>   983000100 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 1丁目 | 01チョウメ
Score,N[3.9940016:15773] : Doc =>   983000101 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 2丁目 | 02チョウメ
Score,N[3.9940016:15774] : Doc =>   983000102 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 3丁目 | 03チョウメ
Score,N[3.9940016:15775] : Doc =>   983000103 | 983-0001 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 4丁目 | 04チョウメ
Score,N[3.9940016:15776] : Doc =>   985090100 | 985-0901 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト | 5丁目 | 05チョウメ
Score,N[3.9940016:15777] : Doc =>   983850200 | 983-8502 | 宮城県 | ミヤギケン | 仙台市宮城野区 | センダイシミヤギノク | 港 | ミナト |  | 
Score,N[3.9940016:41220] : Doc =>   279002400 | 279-0024 | 千葉県 | チバケン | 浦安市 | ウラヤスシ | 港 | ミナト |  | 
Score,N[3.9940016:79921] : Doc =>   437162300 | 437-1623 | 静岡県 | シズオカケン | 御前崎市 | オマエザキシ | 港 | ミナト |  |

ちなみに、AND演算子って両方を必須とするので、クエリの評価結果が

Lucene Query> 東京 AND town:赤羽
入力したクエリ => +prefecture:東京 +town:赤羽

となっていましたよね。

NOT

「NOT」演算子でつなぐことで、検索結果から指定された条件を含む結果を除外することができます。

下記は、東京から、町域に「港」を含まないものを抽出しています。

Lucene Query> 東京 NOT town:港
入力したクエリ => prefecture:東京 -town:港
8,526件、ヒットしました
最初の 10件を表示します
Score,N[2.409595:42534] : Doc =>   100000000 | 100-0000 | 東京都 | トウキョウト | 千代田区 | チヨダク |  |   |  | 
Score,N[2.409595:42535] : Doc =>   102007200 | 102-0072 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42536] : Doc =>   104866000 | 104-8660 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42537] : Doc =>   102812800 | 102-8128 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42538] : Doc =>   102812300 | 102-8123 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42539] : Doc =>   102812200 | 102-8122 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42540] : Doc =>   102812000 | 102-8120 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42541] : Doc =>   102811700 | 102-8117 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42542] : Doc =>   102811200 | 102-8112 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42543] : Doc =>   102810500 | 102-8105 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
-

「AND」と「+」の関係に似ていますね。指定したクエリの結果を除外するようにします。

Lucene Query> 東京 -town:港
入力したクエリ => prefecture:東京 -town:港
8,526件、ヒットしました
最初の 10件を表示します
Score,N[2.409595:42534] : Doc =>   100000000 | 100-0000 | 東京都 | トウキョウト | 千代田区 | チヨダク |  |   |  | 
Score,N[2.409595:42535] : Doc =>   102007200 | 102-0072 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42536] : Doc =>   104866000 | 104-8660 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42537] : Doc =>   102812800 | 102-8128 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42538] : Doc =>   102812300 | 102-8123 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42539] : Doc =>   102812200 | 102-8122 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42540] : Doc =>   102812000 | 102-8120 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42541] : Doc =>   102811700 | 102-8117 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  | 
Score,N[2.409595:42542] : Doc =>   102811200 | 102-8112 | 東京都 | トウキョウト | 千代田区 | チヨダク | 飯田橋 | イイダバシ |  |