mirror of
https://github.com/documize/community.git
synced 2025-07-21 14:19:43 +02:00
Improved full text search matching
This commit is contained in:
parent
eb3bebf20d
commit
f825e9fdc9
9 changed files with 82 additions and 54 deletions
|
@ -1,6 +1,6 @@
|
||||||
/* enterprise edition */
|
/* enterprise edition */
|
||||||
|
|
||||||
-- document lifecycle and versions
|
-- document lifecycle and versioning
|
||||||
ALTER TABLE document ADD COLUMN `lifecycle` INT NOT NULL DEFAULT 1 AFTER `approval`;
|
ALTER TABLE document ADD COLUMN `lifecycle` INT NOT NULL DEFAULT 1 AFTER `approval`;
|
||||||
ALTER TABLE document ADD COLUMN `versioned` INT NOT NULL DEFAULT 0 AFTER `lifecycle`;
|
ALTER TABLE document ADD COLUMN `versioned` INT NOT NULL DEFAULT 0 AFTER `lifecycle`;
|
||||||
ALTER TABLE document ADD COLUMN `versionid` VARCHAR(100) DEFAULT '' NOT NULL AFTER `versioned`;
|
ALTER TABLE document ADD COLUMN `versionid` VARCHAR(100) DEFAULT '' NOT NULL AFTER `versioned`;
|
||||||
|
@ -19,4 +19,9 @@ INSERT INTO permission(orgid, who, whoid, action, scope, location, refid, create
|
||||||
FROM permission
|
FROM permission
|
||||||
WHERE action = 'doc-edit' OR action = 'doc-approve';
|
WHERE action = 'doc-edit' OR action = 'doc-approve';
|
||||||
|
|
||||||
|
-- implement document section name search indexing
|
||||||
|
INSERT INTO search (orgid, documentid, itemid, itemtype, content)
|
||||||
|
SELECT orgid, documentid, refid as itemid, "page" as itemtype, title as content
|
||||||
|
FROM page WHERE status=0
|
||||||
|
|
||||||
-- deprecations
|
-- deprecations
|
||||||
|
|
|
@ -269,6 +269,11 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
if d.Lifecycle == workflow.LifecycleLive {
|
if d.Lifecycle == workflow.LifecycleLive {
|
||||||
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
||||||
go h.Indexer.IndexDocument(ctx, d, a)
|
go h.Indexer.IndexDocument(ctx, d, a)
|
||||||
|
|
||||||
|
pages, _ := h.Store.Page.GetPages(ctx, d.RefID)
|
||||||
|
for i := range pages {
|
||||||
|
go h.Indexer.IndexContent(ctx, pages[i])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
go h.Indexer.DeleteDocument(ctx, d.RefID)
|
go h.Indexer.DeleteDocument(ctx, d.RefID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,12 @@ func (s Scope) IndexContent(ctx domain.RequestContext, p page.Page) (err error)
|
||||||
err = errors.Wrap(err, "execute insert document content entry")
|
err = errors.Wrap(err, "execute insert document content entry")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = ctx.Transaction.Exec("INSERT INTO search (orgid, documentid, itemid, itemtype, content) VALUES (?, ?, ?, ?, ?)",
|
||||||
|
ctx.OrgID, p.DocumentID, p.RefID, "page", p.Title)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute insert document page title entry")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +154,6 @@ func (s Scope) DeleteContent(ctx domain.RequestContext, pageID string) (err erro
|
||||||
// Visible documents include both those in the client's own organisation and those that are public, or whose visibility includes the client.
|
// Visible documents include both those in the client's own organisation and those that are public, or whose visibility includes the client.
|
||||||
func (s Scope) Documents(ctx domain.RequestContext, q search.QueryOptions) (results []search.QueryResult, err error) {
|
func (s Scope) Documents(ctx domain.RequestContext, q search.QueryOptions) (results []search.QueryResult, err error) {
|
||||||
q.Keywords = strings.TrimSpace(q.Keywords)
|
q.Keywords = strings.TrimSpace(q.Keywords)
|
||||||
|
|
||||||
if len(q.Keywords) == 0 {
|
if len(q.Keywords) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -204,29 +209,29 @@ func (s Scope) Documents(ctx domain.RequestContext, q search.QueryOptions) (resu
|
||||||
|
|
||||||
func (s Scope) matchFullText(ctx domain.RequestContext, keywords, itemType string) (r []search.QueryResult, err error) {
|
func (s Scope) matchFullText(ctx domain.RequestContext, keywords, itemType string) (r []search.QueryResult, err error) {
|
||||||
sql1 := `
|
sql1 := `
|
||||||
SELECT
|
SELECT
|
||||||
s.id, s.orgid, s.documentid, s.itemid, s.itemtype,
|
s.id, s.orgid, s.documentid, s.itemid, s.itemtype,
|
||||||
d.labelid as spaceid, COALESCE(d.title,'Unknown') AS document, d.tags, d.excerpt,
|
d.labelid as spaceid, COALESCE(d.title,'Unknown') AS document, d.tags,
|
||||||
|
d.excerpt, d.template, d.versionid,
|
||||||
COALESCE(l.label,'Unknown') AS space
|
COALESCE(l.label,'Unknown') AS space
|
||||||
FROM
|
FROM
|
||||||
search s,
|
search s,
|
||||||
document d
|
document d
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
label l ON l.orgid=d.orgid AND l.refid = d.labelid
|
label l ON l.orgid=d.orgid AND l.refid = d.labelid
|
||||||
WHERE
|
WHERE
|
||||||
s.orgid = ?
|
s.orgid = ?
|
||||||
AND s.itemtype = ?
|
AND s.itemtype = ?
|
||||||
AND s.documentid = d.refid
|
AND s.documentid = d.refid
|
||||||
-- AND d.template = 0
|
AND d.labelid IN
|
||||||
AND d.labelid IN
|
|
||||||
(
|
(
|
||||||
SELECT refid FROM label WHERE orgid=?
|
SELECT refid FROM label WHERE orgid=? AND refid IN
|
||||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
(
|
||||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
|
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND r.userid=?
|
||||||
))
|
)
|
||||||
)
|
)
|
||||||
AND MATCH(s.content) AGAINST(? IN BOOLEAN MODE)`
|
AND MATCH(s.content) AGAINST(? IN BOOLEAN MODE)`
|
||||||
|
|
||||||
err = s.Runtime.Db.Select(&r,
|
err = s.Runtime.Db.Select(&r,
|
||||||
|
@ -235,7 +240,6 @@ func (s Scope) matchFullText(ctx domain.RequestContext, keywords, itemType strin
|
||||||
itemType,
|
itemType,
|
||||||
ctx.OrgID,
|
ctx.OrgID,
|
||||||
ctx.OrgID,
|
ctx.OrgID,
|
||||||
ctx.OrgID,
|
|
||||||
ctx.UserID,
|
ctx.UserID,
|
||||||
ctx.OrgID,
|
ctx.OrgID,
|
||||||
ctx.UserID,
|
ctx.UserID,
|
||||||
|
@ -245,7 +249,6 @@ func (s Scope) matchFullText(ctx domain.RequestContext, keywords, itemType strin
|
||||||
err = nil
|
err = nil
|
||||||
r = []search.QueryResult{}
|
r = []search.QueryResult{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "search document "+itemType)
|
err = errors.Wrap(err, "search document "+itemType)
|
||||||
}
|
}
|
||||||
|
@ -261,25 +264,25 @@ func (s Scope) matchLike(ctx domain.RequestContext, keywords, itemType string) (
|
||||||
keywords = fmt.Sprintf("%%%s%%", keywords)
|
keywords = fmt.Sprintf("%%%s%%", keywords)
|
||||||
|
|
||||||
sql1 := `
|
sql1 := `
|
||||||
SELECT
|
SELECT
|
||||||
s.id, s.orgid, s.documentid, s.itemid, s.itemtype,
|
s.id, s.orgid, s.documentid, s.itemid, s.itemtype,
|
||||||
d.labelid as spaceid, COALESCE(d.title,'Unknown') AS document, d.tags, d.excerpt,
|
d.labelid as spaceid, COALESCE(d.title,'Unknown') AS document, d.tags, d.excerpt,
|
||||||
COALESCE(l.label,'Unknown') AS space
|
COALESCE(l.label,'Unknown') AS space
|
||||||
FROM
|
FROM
|
||||||
search s,
|
search s,
|
||||||
document d
|
document d
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
label l ON l.orgid=d.orgid AND l.refid = d.labelid
|
label l ON l.orgid=d.orgid AND l.refid = d.labelid
|
||||||
WHERE
|
WHERE
|
||||||
s.orgid = ?
|
s.orgid = ?
|
||||||
AND s.itemtype = ?
|
AND s.itemtype = ?
|
||||||
AND s.documentid = d.refid
|
AND s.documentid = d.refid
|
||||||
-- AND d.template = 0
|
-- AND d.template = 0
|
||||||
AND d.labelid IN
|
AND d.labelid IN
|
||||||
(
|
(
|
||||||
SELECT refid FROM label WHERE orgid=?
|
SELECT refid FROM label WHERE orgid=?
|
||||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
|
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
||||||
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||||
|
|
|
@ -12,21 +12,18 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
resultPhrase: "",
|
resultPhrase: '',
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.results = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
let docs = this.get('results');
|
let docs = this.get('results');
|
||||||
let duped = [];
|
let duped = [];
|
||||||
let phrase = 'Nothing found';
|
let phrase = 'Nothing found';
|
||||||
|
|
||||||
if (docs.length > 0) {
|
if (docs.length > 0) {
|
||||||
duped = _.uniq(docs, function (item) {
|
duped = _.uniq(docs, function (item) {
|
||||||
return item.documentId;
|
return item.get('documentId');
|
||||||
});
|
});
|
||||||
|
|
||||||
let references = docs.length === 1 ? "reference" : "references";
|
let references = docs.length === 1 ? "reference" : "references";
|
||||||
|
|
|
@ -24,5 +24,7 @@ export default Model.extend({
|
||||||
space: attr(),
|
space: attr(),
|
||||||
spaceId: attr(),
|
spaceId: attr(),
|
||||||
spaceSlug: attr(),
|
spaceSlug: attr(),
|
||||||
|
template: attr(),
|
||||||
|
versionId: attr(),
|
||||||
selected: attr()
|
selected: attr()
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,4 +39,4 @@ export default Service.extend({
|
||||||
return error;
|
return error;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 0 0 30px 0;
|
margin: 0 0 30px 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
// height: 150px;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
> .checkbox {
|
> .checkbox {
|
||||||
|
@ -33,26 +32,33 @@
|
||||||
|
|
||||||
> .title {
|
> .title {
|
||||||
color: $color-black;
|
color: $color-black;
|
||||||
font-size: 1.3rem;
|
font-weight: bold;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
> .version {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: $color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .space {
|
||||||
|
color: $color-off-black;
|
||||||
|
font-size: 1.2rem;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .snippet {
|
> .snippet {
|
||||||
color: $color-gray;
|
color: $color-gray;
|
||||||
font-size: 1rem;
|
font-size: 1.1rem;
|
||||||
line-height: 24px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $color-gray;
|
|
||||||
|
|
||||||
> .title {
|
> .title {
|
||||||
color: $color-link;
|
color: $color-link;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .snippet {
|
|
||||||
color: $color-link;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +67,7 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 5px 10px 0 5px;
|
margin: 5px 10px 0 5px;
|
||||||
color: $color-gray;
|
color: $color-gray;
|
||||||
font-size: 0.875rem;
|
font-size: 1rem;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -1,15 +1,23 @@
|
||||||
<div class="view-search my-5">
|
<div class="view-search my-5">
|
||||||
<div class="heading">{{resultPhrase}}</div>
|
<div class="heading">{{resultPhrase}}</div>
|
||||||
<ul class="documents">
|
<ul class="documents">
|
||||||
{{#each documents key="id" as |result index|}}
|
{{#each documents key="id" as |result index|}}
|
||||||
<li class="document">
|
<li class="document">
|
||||||
<a class="link" href="s/{{result.spaceId}}/{{result.spaceSlug}}/d/{{ result.documentId }}/{{result.documentSlug}}?page={{ result.itemId }}">
|
<a class="link" href="s/{{result.spaceId}}/{{result.spaceSlug}}/d/{{ result.documentId }}/{{result.documentSlug}}?page={{ result.itemId }}">
|
||||||
<div class="title">{{result.document}}</div>
|
<div class="title">
|
||||||
|
{{result.document}}
|
||||||
|
{{#if (gt result.versionId.length 0)}}
|
||||||
|
<span class="version"> {{result.versionId}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="space">{{result.space}}</div>
|
||||||
<div class="snippet">{{result.excerpt}}</div>
|
<div class="snippet">{{result.excerpt}}</div>
|
||||||
<div class="snippet">({{result.space}})</div>
|
|
||||||
{{folder/document-tags documentTags=result.tags}}
|
{{folder/document-tags documentTags=result.tags}}
|
||||||
</a>
|
{{#if result.template}}
|
||||||
</li>
|
<button type="button" class="mt-3 btn btn-warning text-uppercase font-weight-bold">TEMPLATE</button>
|
||||||
{{/each}}
|
{{/if}}
|
||||||
</ul>
|
</a>
|
||||||
</div>
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -34,4 +34,6 @@ type QueryResult struct {
|
||||||
SpaceID string `json:"spaceId"`
|
SpaceID string `json:"spaceId"`
|
||||||
Space string `json:"space"`
|
Space string `json:"space"`
|
||||||
SpaceSlug string `json:"spaceSlug"`
|
SpaceSlug string `json:"spaceSlug"`
|
||||||
|
Template bool `json:"template"`
|
||||||
|
VersionID string `json:"versionId"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue