Ich habe eine Burgsuch-API mit Elasticsearch + Sudachi + Go + Echo erstellt

Nachdem ich Elasticsearch und Go gelernt hatte, erstellte ich eine Such-API und fasste die Probleme bei der Verwendung und Konfiguration der Ergebnisse zusammen.

Ausführungsumgebung https://github.com/takenoko-gohan/castle-search-api-environment Such-API https://github.com/takenoko-gohan/castle-search-api

Umgebung

In der Umgebungskonstruktion werden Docker und Docker-Compose verwendet.

git clone https://github.com/takenoko-gohan/castle-search-api-environment.git
cd castle-search-api-environment
docker-compose build --no-cache
docker-compose up -d
#Bitte führen Sie nach einer Weile nach dem Start von elasticsearch aus
sh es/script/es_init.sh 

Wie benutzt man

Stellen Sie bei Verwendung der Such-API eine Anfrage in der folgenden Form. Der Abfrageparameter "Schlüsselwort" gibt das Schlüsselwort bei der Suche an. Geben Sie im Abfrageparameter "Präfektur" die Präfektur an, die Sie eingrenzen möchten. Der folgende Befehl sucht nach Burgen, deren Präfektur "Fukushima" ist und das Schlüsselwort "Tsuruga Castle" enthält.

curl -XGET "http://localhost:8080/search?keyword=Tsuruga Schloss&prefecture=Präfektur Fukushima"

Verfassung

Elasticsearch

Indexeinstellung

Der Index wurde wie folgt eingestellt. Zum Zeitpunkt der Suche und des Index verwendet der Analysator den Suchmodus, wenn er in Token unterteilt wird, löscht Teile mit Hilfswörtern, Hilfsverben, Satzzeichen und Lesepunkten und setzt das Token so, dass es in SudachiNormalizedFormAttribute geändert wird.

index_settings.json
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 0,
      "analysis": {
        "tokenizer": {
          "sudachi_tokenizer": {
            "type": "sudachi_tokenizer",
            "split_mode": "C",
            "discard_punctuation": true,
            "resources_path": "/usr/share/elasticsearch/config/sudachi",
            "settings_path": "/usr/share/elasticsearch/config/sudachi/sudachi.json"
          }
        },
        "analyzer": {
          "sudachi_analyzer": {
            "filter": [
              "my_searchfilter",
              "my_posfilter",
              "sudachi_normalizedform"
            ],
            "tokenizer": "sudachi_tokenizer",
            "type": "custom"
          }
        },
        "filter":{
          "my_searchfilter": {
            "type": "sudachi_split",
            "mode": "search"
          },
          "my_posfilter":{
            "type":"sudachi_part_of_speech",
            "stoptags":[
              "Partikel",
              "Hilfsverb",
              "Hilfssymbol,Phrase",
              "Hilfssymbol,Lesepunkt"
            ]
          }
        }
      }
    }
  }
}

Indexzuordnung

Die Indexzuordnung ist wie folgt.

Feld Art Bemerkungen
name text Name des Schlosses
prefectures keyword Präfekturen
rulers text Schlossbesitzer
description text Überblick über die Burg
index_mappings.json
{
  "properties": {
    "name": {"type" : "text", "analyzer": "sudachi_analyzer"},
    "prefecture": {"type": "keyword"},
    "rulers": {"type": "text", "analyzer": "sudachi_analyzer"},
    "description": {"type": "text", "analyzer": "sudachi_analyzer"}
  }
}

Dokument

Der Suchindex ist Wikipedia "[Kategorie: 100 berühmte Schlösser in Japan](https://ja.wikipedia.org/wiki/Category:%E6%97%A5%E6%9C%AC100%E5%90%8D%E5" Die basierend auf "% 9F% 8E)" erstellten Daten werden eingefügt.

Such-API

Die Such-API ist das Go-Sprachframework "echo" und der Elastic Search-Client "go-elasticsearch". Ich habe es mit erstellt. Die API erleichtert das Erstellen und Ausführen einer Abfrage an Elasticsearch basierend auf den zuerst empfangenen Parametern und das Antworten auf den Client wie bei jedem Feld des Dokuments, das die Suche getroffen hat.

Bei der Suche mit dem Abfrageparameter "Schlüsselwort" wird die Punktzahl in der Reihenfolge "Name> Lineale> Beschreibung" mit Boost gewichtet. Bei der Suche mit dem Abfrageparameter "Präfektur" versuchen wir, eine exakte Übereinstimmungssuche für das Feld "Präfektur" durchzuführen.

Abfrage erstellen
package search

func createQuery(q *Query) map[string]interface{} {
	query := map[string]interface{}{}
	if q.Keyword != "" && q.Prefecture != "" {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"bool": map[string]interface{}{
					"must": []map[string]interface{}{
						{
							"bool": map[string]interface{}{
								"should": []map[string]interface{}{
									{
										"match": map[string]interface{}{
											"name": map[string]interface{}{
												"query": q.Keyword,
												"boost": 3,
											},
										},
									},
									{
										"match": map[string]interface{}{
											"rulers": map[string]interface{}{
												"query": q.Keyword,
												"boost": 2,
											},
										},
									},
									{
										"match": map[string]interface{}{
											"description": map[string]interface{}{
												"query": q.Keyword,
												"boost": 1,
											},
										},
									},
								},
								"minimum_should_match": 1,
							},
						},
						{
							"bool": map[string]interface{}{
								"must": []map[string]interface{}{
									{
										"term": map[string]interface{}{
											"prefecture": q.Prefecture,
										},
									},
								},
							},
						},
					},
				},
			},
		}
	} else if q.Keyword != "" && q.Prefecture == "" {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"bool": map[string]interface{}{
					"should": []map[string]interface{}{
						{
							"match": map[string]interface{}{
								"name": map[string]interface{}{
									"query": q.Keyword,
									"boost": 3,
								},
							},
						},
						{
							"match": map[string]interface{}{
								"rulers": map[string]interface{}{
									"query": q.Keyword,
									"boost": 2,
								},
							},
						},
						{
							"match": map[string]interface{}{
								"description": map[string]interface{}{
									"query": q.Keyword,
									"boost": 1,
								},
							},
						},
					},
					"minimum_should_match": 1,
				},
			},
		}
	} else if q.Keyword == "" && q.Prefecture != "" {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"bool": map[string]interface{}{
					"must": []map[string]interface{}{
						{
							"term": map[string]interface{}{
								"prefecture": q.Prefecture,
							},
						},
					},
				},
			},
		}
	}

	return query
}

Problematischer Ort

Als ich den Vorgang nach dem Erstellen vorerst überprüfte, erhielt ich die folgende Antwort.

curl -XGET "http://localhost:8080/search?keyword=Wakamatsu Schloss&prefectures=Präfektur Fukushima"
{
    "message": "Die Suche war erfolgreich.",
    "Results": [
        {
            "name": "Wakamatsu Schloss",
            "prefecture": "Präfektur Fukushima",
            "rulers": [
                "Herr Gamo, Herr Uesugi, Herr Kato, Herr Hoshina, Matsudaira Aizu"
            ],
            "description": "Das Wakamatsu Castle befindet sich in 1 Pursuit Town, Aizu Wakamatsu City, Präfektur Fukushima.-Es ist eine japanische Burg, die in 1 war. Es wird in der Umgebung allgemein als Tsurugajo bezeichnet und außerhalb der Region häufig als Aizu Wakamatsu Castle bezeichnet. In der Literaturgeschichte wird es manchmal als Kurokawa Castle oder Aizu Castle bezeichnet. Als nationale historische Stätte trägt sie den Namen Wakamatsu Castle Ruins."
        },
        {
            "name": "Nihonmatsu Schloss",
            "prefecture": "Präfektur Fukushima",
            "rulers": [
                "Herr Kato",
                "Herr Niwa",
                "Herr Gamo",
                "Herr Nihonmatsu",
                "Herr Uesugi",
                "Mr. Date"
            ],
            "description": "Nihonmatsujo ist eine japanische Burg (Hirayama Castle) in Guo, Stadt Nihonmatsu, Präfektur Fukushima. Eine der 100 berühmten Burgen Japans. Auch bekannt als Kasumiga Castle und Shirahata Castle. Am 26. Juli 2007 wurde es als nationale historische Stätte als Stätte der Burg Nihonmatsu ausgewiesen. Es wurde als "Kasumigajo Park" als einer der 100 besten Aussichtspunkte für Kirschblüten in Japan ausgewählt."
        },
        {
            "name": "Shirakawa Komine Schloss",
            "prefecture": "Präfektur Fukushima",
            "rulers": [
                "Herr Matsudaira",
                "Herr Niwa",
                "Herr Yuki Shirakawa",
                "Herr Gamo",
                "Herr Abe_(Tokugawa Fuyo)"
            ],
            "description": "Das Shirakawa Komine Castle ist ein japanisches Schloss in der Stadt Shirakawa in der Präfektur Fukushima (Shirakawa, Shirakawa-gun, Rikuokukoku). Auch einfach Shirakawa Castle oder Komine Castle genannt. Es ist als nationale historische Stätte ausgewiesen. Darüber hinaus ist es eine der 100 berühmten Burgen in Japan."
        }
    ]
}

Die Suchergebnisse gingen davon aus, dass nur die Burg Wakamatsu getroffen werden würde, aber auch andere Burgen in der Präfektur Fukushima. Als ich überprüfte, wie der folgende Befehl analysiert wurde, scheint Wakamatsu Castle durch "Wakamatsu / Castle" geteilt zu sein. Daher scheinen auch andere Burgen von der "Burg" getroffen worden zu sein, die zum Zeitpunkt der Suche separat geschrieben wurde.

curl -XGET 'http://localhost:9200/castle/_analyze?pretty' -H 'Content-Type: application/json' -d '
{
  "text": "Wakamatsu Schloss",
  "analyzer": "sudachi_analyzer"
}'
{
  "tokens" : [
    {
      "token" : "Wakamatsu",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "Schloss",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    }
  ]
}

Erstellen Sie daher unter Bezugnahme auf diesen Artikel eine CSV-Datei im folgenden Format und erstellen Sie ein Benutzerwörterbuch, in dem die Namen der einzelnen Schlösser im Analysegerät aufgeführt sind. Hat sich registriert.

Wakamatsu Schloss,4786,4786,5000,Wakamatsu Schloss,Substantiv,固有Substantiv,Allgemeines,*,*,*,Wakamatsujo,Wakamatsu Schloss,*,*,*,*,*

Nachdem ich mich im Benutzerwörterbuch registriert hatte, überprüfte ich die Analyseergebnisse, aber diesmal wurde es die richtige Nomenklatur "Wakamatsu Castle".

curl -XGET 'http://localhost:9200/castle/_analyze?pretty' -H 'Content-Type: application/json' -d '
{
  "text": "Wakamatsu Schloss",
  "analyzer": "sudachi_analyzer"
}'
{
  "tokens" : [
    {
      "token" : "Wakamatsu Schloss",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0
    }
  ]
}

Als ich erneut mit der Such-API suchte, traf nur Wakamatsu Castle wie erwartet.

curl -XGET "http://localhost:8080/search?keyword=Wakamatsu Schloss&prefecture=Präfektur Fukushima"
{
    "message": "Die Suche war erfolgreich.",
    "Results": [
        {
            "name": "Wakamatsu Schloss",
            "prefecture": "Präfektur Fukushima",
            "rulers": [
                "Herr Gamo, Herr Uesugi, Herr Kato, Herr Hoshina, Matsudaira Aizu"
            ],
            "description": "Das Wakamatsu Castle befindet sich in 1 Pursuit Town, Aizu Wakamatsu City, Präfektur Fukushima.-Es ist eine japanische Burg, die in 1 war. Es wird in der Umgebung allgemein als Tsurugajo bezeichnet und außerhalb der Region häufig als Aizu Wakamatsu Castle bezeichnet. In der Literaturgeschichte wird es manchmal als Kurokawa Castle oder Aizu Castle bezeichnet. Als nationale historische Stätte trägt sie den Namen Wakamatsu Castle Ruins."
        }
    ]
}

Es trat jedoch ein anderes Problem auf. Dieses Mal, als ich in Wakamatsu und in der Präfektur Fukushima nach Schlüsselwörtern suchte, wurden keine Treffer gefunden. Durch die Registrierung des Benutzerwörterbuchs scheint Wakamatsu Castle nicht getroffen zu haben, da es nicht mehr durch "Wakamatsu / Castle" geteilt wurde.

curl -XGET "http://localhost:8080/search?keyword=Wakamatsu&prefecture=Präfektur Fukushima"
{
    "message": "Die Suche war erfolgreich.",
    "Results": null
}

Laut hier können Informationen zur Aufteilung in A-Einheiten in der 16. Spalte der CSV-Datei beschrieben werden. ist. Daher habe ich die CSV-Datei in der folgenden Form so geändert, dass sie im Suchmodus in C-Einheiten und A-Einheiten unterteilt werden kann. (Nur Wakamatsu Castle, Nihonmatsu Castle und Shirakawa Komine Castle ...)

Wakamatsu Schloss,4786,4786,5000,Wakamatsu Schloss,Substantiv,固有Substantiv,Allgemeines,*,*,*,Wakamatsujo,Wakamatsu Schloss,*,C,650091/368637,*,*
Nihonmatsu Schloss,4786,4786,5000,Nihonmatsu Schloss,Substantiv,固有Substantiv,Allgemeines,*,*,*,Japanischer Matsujo,Nihonmatsu Schloss,*,C,281483/368637,*,*
Shirakawa Komine Schloss,4786,4786,5000,Shirakawa Komine Schloss,Substantiv,固有Substantiv,Allgemeines,*,*,*,Shirakawa Kominejo,Shirakawa Komine Schloss,*,C,584799/394859/368637,*,*
curl -XGET 'http://localhost:9200/castle/_analyze?pretty' -H 'Content-Type: application/json' -d '
{
  "text": "Wakamatsu Schloss",
  "analyzer": "sudachi_analyzer"
}'
{
  "tokens" : [
    {
      "token" : "Wakamatsu Schloss",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0,
      "positionLength" : 2
    },
    {
      "token" : "Wakamatsu",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "Schloss",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    }
  ]
}

Selbst wenn Sie in Wakamatsu und in der Präfektur Fukushima nach Schlüsselwörtern suchen, wird Wakamatsu Castle ein Hit. Es ist schwer, die gewünschte Suche zu finden.

curl  -XGET "http://localhost:8080/search?keyword=Wakamatsu Schloss&prefecture=Präfektur Fukushima"
{
    "message": "Die Suche war erfolgreich.",
    "Results": [
        {
            "name": "Wakamatsu Schloss",
            "prefecture": "Präfektur Fukushima",
            "rulers": [
                "Herr Gamo, Herr Uesugi, Herr Kato, Herr Hoshina, Matsudaira Aizu"
            ],
            "description": "Das Wakamatsu Castle befindet sich in 1 Pursuit Town, Aizu Wakamatsu City, Präfektur Fukushima.-Es ist eine japanische Burg, die in 1 war. Es wird in der Umgebung allgemein als Tsurugajo bezeichnet und außerhalb der Region häufig als Aizu Wakamatsu Castle bezeichnet. In der Literaturgeschichte wird es manchmal als Kurokawa Castle oder Aizu Castle bezeichnet. Als nationale historische Stätte trägt sie den Namen Wakamatsu Castle Ruins."
        }
    ]
}

Referenz

Praktisch zum Erstellen eines Benutzerwörterbuchs mit Elasticsearch + Sudachi + Docker So erstellen Sie ein Sudachi-Benutzerwörterbuch elasticsearch-sudachi README go-elasticsearch README

Recommended Posts

Ich habe eine Burgsuch-API mit Elasticsearch + Sudachi + Go + Echo erstellt
Ich habe eine Web-API erstellt
Ich habe versucht, mit Go einen exklusiven Kontrollmechanismus zu erstellen
Ich habe versucht, "Sakurai-san" LINE BOT mit API Gateway + Lambda zu erstellen
Ich habe versucht, eine einfache Bilderkennungs-API mit Fast API und Tensorflow zu erstellen
[5.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Rubyist hat versucht, eine einfache API mit Python + Flasche + MySQL zu erstellen
[2nd] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
[3.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich möchte den vollständigen Text mit elasticsearch + python durchsuchen
Ich habe versucht, mit Selenium und Python einen regelmäßigen Ausführungsprozess durchzuführen
Ich habe versucht, mit Python eine 2-Kanal-Post-Benachrichtigungsanwendung zu erstellen
Ich habe versucht, eine ToDo-App mit einer Flasche mit Python zu erstellen
[4.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
[1.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich habe versucht, Jojo mit LSTM ein seltsames Zitat zu machen
Ich habe versucht, mit Raspeye 4 (Python Edition) ein signalähnliches Signal zu erzeugen.
Ich habe versucht, einen URL-Verkürzungsdienst mit AWS CDK serverlos zu machen
Ich möchte ein Spiel mit Python machen
Ich habe ein ○ ✕ Spiel mit TensorFlow gemacht
Ich habe versucht, einen periodischen Prozess mit CentOS7, Selenium, Python und Chrome durchzuführen
Ich habe eine einfache Mail-Sendeanwendung mit tkinter von Python erstellt
Als ich versuchte, eine VPC mit AWS CDK zu erstellen, konnte ich es aber nicht schaffen
[Patentanalyse] Ich habe versucht, mit Python eine Patentkarte zu erstellen, ohne Geld auszugeben
Ich habe versucht, einen "verdammt großen Literaturkonverter" zu machen.
[Go + Gin] Ich habe versucht, eine Docker-Umgebung zu erstellen
Ich habe versucht, unsere Dunkelheit mit der Chatwork-API aufzudecken
Ich habe versucht, eine OCR-App mit PySimpleGUI zu erstellen
Ich habe versucht, mit dem Seq2Seq-Modell von TensorFlow so etwas wie einen Chatbot zu erstellen
Ich habe versucht, mit Elasticsearch Ranking zu lernen!
Ich habe versucht, mit AI kreative Kunst zu machen! Ich habe eine Neuheit programmiert! (Artikel: Creative Adversarial Network)
Ich habe versucht, eine Klasse für die Suche nach Dateien mit der Glob-Methode von Python in VBA zu erstellen
Ich habe versucht, mit Quantx eine Linie mit gleitendem Durchschnitt des Volumens zu implementieren
Ich habe versucht, Videos mit der Youtube Data API (Anfänger) zu suchen.
Ich habe versucht, mit Python faker verschiedene "Dummy-Daten" zu erstellen
Ich möchte einen Blog-Editor mit dem Administrator von Django erstellen
Ich möchte ein Klickmakro mit pyautogui (Wunsch) erstellen.
Ich habe versucht, das Problem der Kombinationsoptimierung mit Qiskit zu lösen
Ich möchte ein Klickmakro mit pyautogui (Outlook) erstellen.
Ich habe versucht, mit Hy ・ Define a class zu beginnen
Ich habe versucht, eine zufällige FizzBuzz-Spalte mit Blasensortierung zu sortieren.
Ich habe eine Stoppuhr mit tkinter mit Python gemacht
Ich habe versucht, die Benutzeroberfläche neben Python und Tkinter dreiäugig zu gestalten
Ich habe versucht, in einem tief erlernten Sprachmodell zu schreiben
Ich habe mit PyQt einen einfachen Texteditor erstellt
[1 Stunde Herausforderung] Ich habe versucht, eine Wahrsagerseite zu erstellen, die für Python zu geeignet ist
Ich habe versucht, mit Kendra, das bei re: Invent 2019 angekündigt wurde, sofort einen Befehl zum Durchsuchen der Dokumentensuche auszuführen
Ich habe versucht, einen Generator zu erstellen, der mit Python eine C # -Containerklasse aus CSV generiert
Ich habe versucht, mit OpenCV eine Bewegungserkennungsüberwachungskamera mit einer WEB-Kamera mit Raspberry Pi herzustellen
Ich habe versucht, eine Quip-API zu erstellen
Ich habe Teslas API berührt
Ich habe versucht, Deep Learning mit Spark × Keras × Docker skalierbar zu machen
Ein Memorandum beim automatischen Erwerb mit Selen
Ich habe versucht, mit Python einen regulären Ausdruck für "Betrag" zu erstellen