Skip to content

Commit 77707c2

Browse files
committed
Issue search support elasticsearch
1 parent 2399bad commit 77707c2

File tree

284 files changed

+57021
-21
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

284 files changed

+57021
-21
lines changed

.drone.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ services:
8686
pull: default
8787
image: gitea/test-openldap:latest
8888

89+
- name: elasticsearch
90+
pull: default
91+
environment:
92+
discovery.type: single-node
93+
image: elasticsearch:7.5.0
94+
8995
steps:
9096
- name: fetch-tags
9197
pull: default

custom/conf/app.ini.sample

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,10 @@ CONN_MAX_LIFETIME = 3s
368368
MAX_OPEN_CONNS = 0
369369

370370
[indexer]
371-
; Issue indexer type, currently support: bleve or db, default is bleve
371+
; Issue indexer type, currently support: bleve, db or elasticsearch, default is bleve
372372
ISSUE_INDEXER_TYPE = bleve
373+
; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch
374+
ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
373375
; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve
374376
ISSUE_INDEXER_PATH = indexers/issues.bleve
375377
; Issue indexer queue, currently support: channel, levelqueue or redis, default is levelqueue

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ relation to port exhaustion.
228228

229229
## Indexer (`indexer`)
230230

231-
- `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently support: bleve or db, if it's db, below issue indexer item will be invalid.
231+
- `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently support: bleve, db or elasticsearch, if it's db, below issue indexer item will be invalid.
232+
- `ISSUE_INDEXER_CONN_STR`: ****: Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch. i.e. http://elastic:changeme@localhost:9200
232233
- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search.
233234
- The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility:
234235
- `ISSUE_INDEXER_QUEUE_TYPE`: **levelqueue**: Issue indexer queue, currently supports:`channel`, `levelqueue`, `redis`.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ require (
7474
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
7575
github.com/niklasfasching/go-org v0.1.9
7676
github.com/oliamb/cutter v0.2.2
77+
github.com/olivere/elastic/v7 v7.0.9
7778
github.com/pkg/errors v0.8.1
7879
github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e
7980
github.com/prometheus/client_golang v1.1.0

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
6868
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
6969
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
7070
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
71+
github.com/aws/aws-sdk-go v1.25.25/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
7172
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
7273
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
7374
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -154,6 +155,8 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQD
154155
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
155156
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
156157
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
158+
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
159+
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
157160
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
158161
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
159162
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -248,6 +251,7 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ
248251
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
249252
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
250253
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
254+
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
251255
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
252256
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
253257
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -322,6 +326,7 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
322326
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
323327
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
324328
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
329+
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
325330
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
326331
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
327332
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
@@ -411,13 +416,16 @@ github.com/niklasfasching/go-org v0.1.9/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUv
411416
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
412417
github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k=
413418
github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU=
419+
github.com/olivere/elastic/v7 v7.0.9 h1:+bTR1xJbfLYD8WnTBt9672mFlKxjfWRJpEQ1y8BMS3g=
420+
github.com/olivere/elastic/v7 v7.0.9/go.mod h1:2TeRd0vhLRTK9zqm5xP0uLiVeZ5yUoL7kZ+8SZA9r9Y=
414421
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
415422
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
416423
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
417424
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
418425
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
419426
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
420427
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
428+
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
421429
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
422430
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
423431
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
@@ -486,6 +494,7 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
486494
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
487495
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
488496
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
497+
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
489498
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
490499
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
491500
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
@@ -573,6 +582,7 @@ go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL
573582
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
574583
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
575584
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
585+
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
576586
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
577587
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
578588
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=

integrations/mysql.ini.tmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ PASSWD = {{TEST_MYSQL_PASSWORD}}
1010
SSL_MODE = disable
1111

1212
[indexer]
13+
ISSUE_INDEXER_TYPE = elasticsearch
14+
ISSUE_INDEXER_CONN_STR = http://elastic:changeme@elasticsearch:9200
1315
ISSUE_INDEXER_PATH = integrations/indexers-mysql/issues.bleve
1416
REPO_INDEXER_ENABLED = true
1517
REPO_INDEXER_PATH = integrations/indexers-mysql/repos.bleve
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package issues
6+
7+
import (
8+
"context"
9+
"errors"
10+
"fmt"
11+
"strconv"
12+
"time"
13+
14+
"code.gitea.io/gitea/modules/log"
15+
16+
"github.com/olivere/elastic/v7"
17+
)
18+
19+
var (
20+
_ Indexer = &ElasticSearchIndexer{}
21+
)
22+
23+
// ElasticSearchIndexer implements Indexer interface
24+
type ElasticSearchIndexer struct {
25+
client *elastic.Client
26+
indexerName string
27+
typeName string
28+
}
29+
30+
type elasticLogger struct {
31+
*log.Logger
32+
}
33+
34+
func (l elasticLogger) Printf(format string, args ...interface{}) {
35+
l.Logger.Log(2, l.Logger.GetLevel(), format, args...)
36+
}
37+
38+
// NewElasticSearchIndexer creates a new elasticsearch indexer
39+
func NewElasticSearchIndexer(url, indexerName string) (*ElasticSearchIndexer, error) {
40+
opts := []elastic.ClientOptionFunc{
41+
elastic.SetURL(url),
42+
elastic.SetSniff(false),
43+
elastic.SetHealthcheckInterval(10 * time.Second),
44+
elastic.SetGzip(false),
45+
}
46+
47+
logger := elasticLogger{log.GetLogger(log.DEFAULT)}
48+
49+
if logger.GetLevel() == log.TRACE || logger.GetLevel() == log.DEBUG {
50+
opts = append(opts, elastic.SetTraceLog(logger))
51+
} else if logger.GetLevel() == log.ERROR || logger.GetLevel() == log.CRITICAL || logger.GetLevel() == log.FATAL {
52+
opts = append(opts, elastic.SetErrorLog(logger))
53+
} else if logger.GetLevel() == log.INFO || logger.GetLevel() == log.WARN {
54+
opts = append(opts, elastic.SetInfoLog(logger))
55+
}
56+
57+
client, err := elastic.NewClient(opts...)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
return &ElasticSearchIndexer{
63+
client: client,
64+
indexerName: indexerName,
65+
typeName: "indexer_data",
66+
}, nil
67+
}
68+
69+
const (
70+
defaultMapping = `{
71+
"mappings": {
72+
"properties": {
73+
"id": {
74+
"type": "integer",
75+
"index": true
76+
},
77+
"repo_id": {
78+
"type": "integer",
79+
"index": true
80+
},
81+
"title": {
82+
"type": "text",
83+
"index": true
84+
},
85+
"content": {
86+
"type": "text",
87+
"index": true
88+
},
89+
"comments": {
90+
"type" : "text",
91+
"index": true
92+
}
93+
}
94+
}
95+
}`
96+
)
97+
98+
// Init will initial the indexer
99+
func (b *ElasticSearchIndexer) Init() (bool, error) {
100+
ctx := context.Background()
101+
exists, err := b.client.IndexExists(b.indexerName).Do(ctx)
102+
if err != nil {
103+
return false, err
104+
}
105+
106+
if !exists {
107+
var mapping = defaultMapping
108+
109+
createIndex, err := b.client.CreateIndex(b.indexerName).BodyString(mapping).Do(ctx)
110+
if err != nil {
111+
return false, err
112+
}
113+
if !createIndex.Acknowledged {
114+
return false, errors.New("init failed")
115+
}
116+
117+
return false, nil
118+
}
119+
return true, nil
120+
}
121+
122+
// Index will save the index data
123+
func (b *ElasticSearchIndexer) Index(issues []*IndexerData) error {
124+
if len(issues) == 0 {
125+
return nil
126+
} else if len(issues) == 1 {
127+
issue := issues[0]
128+
_, err := b.client.Index().
129+
Index(b.indexerName).
130+
Id(fmt.Sprintf("%d", issue.ID)).
131+
BodyJson(map[string]interface{}{
132+
"id": issue.ID,
133+
"repo_id": issue.RepoID,
134+
"title": issue.Title,
135+
"content": issue.Content,
136+
"comments": issue.Comments,
137+
}).
138+
Do(context.Background())
139+
return err
140+
}
141+
142+
reqs := make([]elastic.BulkableRequest, 0)
143+
for _, issue := range issues {
144+
reqs = append(reqs,
145+
elastic.NewBulkIndexRequest().
146+
Index(b.indexerName).
147+
//Type(b.typeName).
148+
Id(fmt.Sprintf("%d", issue.ID)).
149+
Doc(map[string]interface{}{
150+
"id": issue.ID,
151+
"repo_id": issue.RepoID,
152+
"title": issue.Title,
153+
"content": issue.Content,
154+
"comments": issue.Comments,
155+
}),
156+
)
157+
}
158+
159+
_, err := b.client.Bulk().
160+
Index(b.indexerName).
161+
Add(reqs...).
162+
Do(context.Background())
163+
return err
164+
}
165+
166+
// Delete deletes indexes by ids
167+
func (b *ElasticSearchIndexer) Delete(ids ...int64) error {
168+
if len(ids) == 0 {
169+
return nil
170+
} else if len(ids) == 1 {
171+
_, err := b.client.Delete().
172+
Index(b.indexerName).
173+
Id(fmt.Sprintf("%d", ids[0])).
174+
Do(context.Background())
175+
return err
176+
}
177+
178+
reqs := make([]elastic.BulkableRequest, 0)
179+
for _, id := range ids {
180+
reqs = append(reqs,
181+
elastic.NewBulkDeleteRequest().
182+
Index(b.indexerName).
183+
Id(fmt.Sprintf("%d", id)),
184+
)
185+
}
186+
187+
_, err := b.client.Bulk().
188+
Index(b.indexerName).
189+
Add(reqs...).
190+
Do(context.Background())
191+
return err
192+
}
193+
194+
// Search searches for issues by given conditions.
195+
// Returns the matching issue IDs
196+
func (b *ElasticSearchIndexer) Search(keyword string, repoIDs []int64, limit, start int) (*SearchResult, error) {
197+
kwQuery := elastic.NewMultiMatchQuery(keyword, "title", "content", "comments")
198+
query := elastic.NewBoolQuery()
199+
query = query.Must(kwQuery)
200+
if len(repoIDs) > 0 {
201+
var repoStrs = make([]interface{}, 0, len(repoIDs))
202+
for _, repoID := range repoIDs {
203+
repoStrs = append(repoStrs, repoID)
204+
}
205+
repoQuery := elastic.NewTermsQuery("repo_id", repoStrs...)
206+
query = query.Must(repoQuery)
207+
}
208+
searchResult, err := b.client.Search().
209+
Index(b.indexerName).
210+
Query(query).
211+
Sort("id", true).
212+
From(start).Size(limit).
213+
Do(context.Background())
214+
if err != nil {
215+
return nil, err
216+
}
217+
218+
hits := make([]Match, 0, limit)
219+
for _, hit := range searchResult.Hits.Hits {
220+
id, _ := strconv.ParseInt(hit.Id, 10, 64)
221+
hits = append(hits, Match{
222+
ID: id,
223+
})
224+
}
225+
226+
return &SearchResult{
227+
Total: searchResult.TotalHits(),
228+
Hits: hits,
229+
}, nil
230+
}
231+
232+
// Close implements indexer
233+
func (b *ElasticSearchIndexer) Close() {}

0 commit comments

Comments
 (0)